WT Toolkit 0.3.3

wt_widget.js

Summary

This file contains all non-vector and non-form visible widgets


Class Summary
wtAnchor A wtAnchor can be used in two ways:

It can be used as a traditional HTML anchor (i.e. a hyperlink) by setting a href attribute to it via setHref()
Or, it can be used as a text-only button by setting an event handler to it via setHandler()
wtAttachedMenu A popup menu attached to some widget.
wtBlockSpacer An area of empty space with block layout.
wtButton This class provides you a typical image-based button with graphical effects.
wtColumnLayout A widget that layouts it schild widgets along a column.
wtContextMenu A popup menu that appears when the user right clicks on a widget.
wtDisplay A tabular display with an optional caption.
wtDisplayCell A table cell used in wtDisplay.
wtDisplayRow A display row used in a display table.
wtImage A raster image object.
wtModalWindow A wtModalwindow is similar to wtWindow, except that it is created modal by default.
wtNotebook A basic tabbed container.
wtNotebookPage A tabbed page container for use with wtNotebook.
wtPopupMenu A basic popup menu with soft drop shadow, this class is not meant to be used in a web application directly.
wtRowLayout A widget that layouts its child widgets along a row.
wtShadowWidget This widget is a container that adds a soft drop shadow around the rectangular bounding box around its contents
wtSpacer An area of empty space with inline layout.
wtTextBlock A shadowed text block.
wtTreeNode A tree node, freely expandable to form a tree.
wtView A view container in WT Toolkit is a fixed size container with automatic scroll bars and optional borders It is typically used as a part of more sophisticated widget containes, e.g. a wtWindow
wtWidget The base class of all visible widgets.
wtWindow A wtWindow is a draggable container widget with a title bar (empty by default), a wtView container area and soft drop shadow

// vim: set tabstop=4 shiftwidth=4 foldmethod=marker:
/*
    WT Toolkit - Web UI logic toolkit. Copyright (C) 2006 Kou Man Tong

    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
*/

/*
 * $Log: wt_widget.js,v $
 * Revision 1.37  2007/03/27 20:37:41  francium
 * -Fixed: DOM nodes with wtDependency are not checked by the garbage collector
 *         correctly
 * -Added: wtGraph class
 *
 * Revision 1.36  2007/03/24 19:32:00  francium
 * -Fixed: "_$() is not a function" errors on page load
 * -Added: MouseOver and MouseOut signals for wtVectorGroup
 * -Added: Translucent effects for wtBar
 * -Added: wtColorGenerator::spin() operation
 * -Improved: wtChart's color selection mechanism
 * -Improved: Vector widget demo
 *
 * Revision 1.35  2007/03/24 08:23:16  francium
 * -Fixed: "wtObject not defined" error on page load
 * -Fixed: Errors being ignored within event handlers
 *
 * Revision 1.34  2007/03/24 07:44:13  francium
 * -Added: WTObjectManager::scheduleGC() which enables the programmer to schedule
 *         GC more liberally without worrying about repeated garbage collections
 * -Improved: wtGraphEdge can now let the user add/remove anchor points and
 *         change the coordinates of anchor points by mouse actions
 *
 * Revision 1.33  2007/03/22 13:20:44  francium
 * *** empty log message ***
 *
 * Revision 1.32  2007/03/18 17:32:57  francium
 * *** empty log message ***
 *
 * Revision 1.31  2007/03/17 05:07:19  francium
 * -Fixed: wtWidget::getScreenPosition still calculating wrong coordinates in
 *         IE
 * -Fixed: wtPopupMenu and wtContextMenu calculates wrong popup coordinates
 *
 * Revision 1.30  2007/03/16 20:06:21  francium
 * -Fixed: wtWidget::getScreenPosition does not work when Firefox when the window
 *         is scrolled
 *
 * Revision 1.29  2007/03/16 07:37:45  francium
 * -Fixed: wtRoot CSS class missing from wtWidget
 * -Added: wt_vector.js as one of the include JS files from wt_core.js
 *
 * Revision 1.28  2007/03/13 07:32:15  francium
 * -Added: wtVectorGroup class in wt_vector.js
 *
 * Revision 1.27  2007/03/12 15:24:21  francium
 * -Removed: Vector graphics logic from wt_widget.js
 *
 * Revision 1.26  2007/03/09 16:56:44  marco
 * *** empty log message ***
 *
 * Revision 1.25  2007/03/09 16:32:39  francium
 * -Added: Summary and project name in API documentation
 *
 * Revision 1.24  2007/03/08 17:57:53  francium
 * -Fixed: Disabling a wtSpreadsheet should have visual effects on the widget to
 *         indicate that it is disabled to the user
 * -Added: JSDoc entries in wt_form.js
 *
 * Revision 1.23  2007/03/08 05:23:09  francium
 * -Added: JSDoc documentation compiler under redist
 * -Added: JSDoc entries in wt_widget.js
 * -Added: JSDoc entries in wt_algor.js
 * -Added: JSDoc entries in wt_wm.js
 * -Added: JSDoc entries in wt_mouse.js
 * -Added: JSDoc entries in wt_core.js
 * -Fixed: Random MSIE() not defined errors during page load
 *
 * Revision 1.22  2007/03/07 17:35:17  francium
 * -Added: JSDoc entries in wt_widget.js
 *
 * Revision 1.21  2007/02/28 01:16:35  francium
 * -Fixed: Duplicated label "2006" in index_vector_graphics.js
 * -Fixed: wtWidget constructor cannot add SVG elements with a DOM node parent
 * -Fixed: JS file synchronization problem in graphical unit test cases
 * -Added: Garbage collection points in graphical unit test cases
 *
 * Revision 1.20  2007/02/24 00:28:32  francium
 * -Fixed: Logical error in hasSvgRoot flag - the flag does not account for the
 *         possibility of the widget being cleared
 * -Improved: Vector graphics demo now draw the graphical widgets only when a
 *         notebook page is selected, for improving loading time in IE
 *
 * Revision 1.19  2007/02/20 00:29:58  francium
 * -Changed: Renamed wtObject::wtDependencies to wtObject::wtDependency and the
 *         attribute is no longer an array
 * -Changed: Manual GC is now the default behavior
 * -Removed: window.disableGCThread flag since GC Thread is no longer the default
 * -Changed: Added a "?tx=ab" dummy argument after .js file references in HTML
 *         files to avoid version synchronization problems
 *
 * Revision 1.18  2007/02/14 16:01:20  francium
 * -Fixed: Cached .JS and .CSS files on client side may not be in sync with the
 *         server version
 *
 * Revision 1.17  2007/01/12 16:24:33  francium
 * -Improved: Added a simple optimization to garbage collection helper algorithm
 *
 * Revision 1.16  2007/01/12 14:51:51  marco
 * -Modified: vml and svg objects are merged and created in wtWidget
 *
 * Revision 1.15  2007/01/11 16:52:27  francium
 * -Fixed: Number of mandatory arguments for wtRemoteProcedureCall incorretly set
 *         to 3, should be 2 instead
 * -Added: wtObject::addDependency() function
 * -Fixed: wtWindow::ucenter() does not work
 * -Fixed: wtModalWindow positioning algorithm does not work
 *
 * Revision 1.14  2007/01/11 15:21:10  francium
 * -Fixed: wtWidget::getScreenPosition() does not work
 * -Changed: Converted demo pages index.js and index2.js to use the new object
 *         model
 *
 * Revision 1.13  2007/01/11 11:54:22  francium
 * -Changed: Finished porting wt_form.js to 0.2.0 object structure
 * -Added: Unit test cases for all wt_form.js objects
 * -Changed: Generalized domDependencies into wtDependencies in garbage collector
 *         helper algorithm
 * -Fixed: wtWindow::clearAll() crashes Internet Explorer
 *
 * Revision 1.12  2007/01/08 16:48:42  francium
 * -Fixed: wtRemoteProcedureCall:setHandler() and setFailHandler() not working
 * -Added: Unit test case for wtRemoteProcedureCall
 *
 * Revision 1.11  2007/01/07 18:25:07  francium
 * -Fixed: wtRemoteProcedureCall object cannot be created
 * -Changed: Converted wtForm, wtFormWidget and wtSingleLineTextInput to use new
 *         object system
 * -Added: prevValue and getPrevValue() to wtFormWidget
 * -Added: prevValue as an argument to wtSingleLineTextInput validator
 * -Added: ValueChanged signal to wtForm
 * -Changed: General format of arguments to ValueChanged signal
 *
 * Revision 1.10  2007/01/06 17:42:18  francium
 * -Added: Weak reference emulation, proxy pattern and observer pattern
 *          implenentation via wtObject
 * -Changed: Converted wt_core.js, wt_mouse.js, wt_wm.js, wt_widget.js to use
 *         prototype based inheritance in Javascript and wtObject as the root
 *         superclass
 * -Added: Unit test cases for all widgets in wt_widget.js and wt_wm.js
 *
 * Revision 1.8  2006/12/25 16:03:48  francium
 * -Fixed: Cross-URL memory leak in IE
 * -Fixed: Memory leaks related to observing DOM objects that has gone out of
 * 	the DOM tree and is no longer useful
 *
 * Revision 1.7  2006/12/24 16:51:03  francium
 * -Fixed: Shadow polling hack for IE gives out "Unspecified error"
 *
 * Revision 1.6  2006/12/24 16:38:38  francium
 * -Fixed: fill-opacity not supported by regular HTML elements
 *
 * Revision 1.5  2006/12/24 16:18:23  francium
 * -Fixed: Missing isEnabled() functions in wt_widget.js across many widgets
 *
 * Revision 1.4  2006/12/24 16:13:42  francium
 * -Fixed: isEnabled() not working across many widgets
 *
 * Revision 1.3  2006/12/24 12:29:16  francium
 * -Fixed: wtForm::submitExclude and wtRemoteProcedureCall::submitExclude
 * 	re-enables widgets that are disabled before sending RPC request to
 * 	server
 * -Fixed: Wrongly placed copyright notice, should be near the top of the file
 *
 * $Id: wt_widget.js,v 1.37 2007/03/27 20:37:41 francium Exp $
 */

/**
  @fileoverview This file contains all non-vector and non-form visible widgets
  */

// {{{ wtBindSignal() - gives a widget some basic signals that every DOM element should have
/**
  Gives a wtWidget some basic signals that every DOM node should have
  @private
  */
var wtBindSignal = function(_retval)
{
	if (!_retval)
		return;
	_retval.linkSignal("Click", "onclick");
	_retval.linkSignal("MouseDown", "onmousedown");
	_retval.linkSignal("MouseOver", "onmouseover");
	_retval.linkSignal("MouseOut", "onmouseout");
	_retval.linkSignal("MouseUp", "onmouseup");
	_retval.linkSignal("Focus", "onfocus");
	_retval.linkSignal("Blur", "onblur");
	_retval.linkSignal("DoubleClick", "ondblclick");
	_retval.linkSignal("KeyDown", "onkeydown");
	_retval.linkSignal("KeyUp", "onkeyup");
	_retval.linkSignal("KeyPress", "onkeypress");
	_retval.linkSignal("Resize", "onresize");
}
// }}}
// {{{ wtWidget - the root widget object
/**
  Constructs a widget based on a DOM node
  @class The base class of all visible widgets. <br/><br/>
  Available signals:<br/>
  <ul>
  <li>Click</li>
  <li>MouseDown</li>
  <li>MouseOver</li>
  <li>MouseOut</li>
  <li>MouseUp</li>
  <li>Focus</li>
  <li>Blur</li>
  <li>DoubleClick</li>
  <li>KeyDown</li>
  <li>KeyUp</li>
  <li>KeyPress</li>
  <li>Resize</li>
  <li>Move</li>
  <li>DragStart</li>
  <li>DragEnd</li>
  </ul>
  @constructor
  @param {wtWidget} _parent The container widget to add this widget to. Can also be a DOM node like document.body. Fill in null if you don't want to immediately add this widget to a container.
  @param {String} _tagName The new DOM node's HTML tag
  */
var wtWidget = function(_parent, _tagName)
{
	if (arguments.length < 2)
		return;
 	var domNode;
	var tag = _tagName.toLowerCase();
	domNode = document.createElement(_tagName);
	this.startProxy(domNode);
	$_(this).id = this.toString();

	domNode.className = "wtRoot";
	if (domNode["style"] == undefined)
		domNode["style"] = {};
	
	wtBindSignal(this);

	this.setRelativePosition(0,0);
	this.setLevel(0);

	if (_tagName.toLowerCase() == "td" || _tagName.toLowerCase() == "div" || _tagName.toLowerCase() == "span")
		domNode.align = "left";

	var _noStyle = {"tr":1, "tbody":1};
	
	// IE sucks - it needs special cases otherwise it won't work
	var _noTranslucency = {"tr":1, "tbody":1, "td":1, "th":1};
	if (isMSIE() && _noTranslucency[_tagName.toLowerCase()] == undefined)
		domNode.style.filter = "progid:DXImageTransform.Microsoft.Alpha(opacity=100,enabled=false)";

	// set some default slots and signals
	this.setSlot("Drag", this.dragSlot);
	this.setSlot("SetDragging", this.setDraggingSlot);
	this.setSlot("UnsetDragging", this.unsetDraggingSlot);
	this.setSignal("Move");
	this.setSignal("DragStart");
	this.setSignal("DragEnd");

	if (_parent)
	{
		if (isDOMNode(_parent))
			_parent.appendChild(domNode);
		else
			_parent.addWidget(this);
	}
}
wtWidget.prototype = new wtObject;
/**
  Sets the widget's position to static. i.e. follow the natural document flow <br/>
  */
wtWidget.prototype.setStaticPosition = function() {
	$_(this).style.position = "static";
	this.emit("Move", new wt2DPoint(this.get("offsetLeft"), this.get("offsetTop")));
}
/**
  Sets the widget's position to (+x, +y) relative to its natural position <br/>
  @param {Number} x The widget's offset on x-axis
  @param {Number} y The widget's offset on y-axis
  */
wtWidget.prototype.setRelativePosition = function(x, y) 
{
	$_(this).style.position = "relative";
	$_(this).style.left = x + "px";
	$_(this).style.top = y + "px";
	this.emit("Move", new wt2DPoint(this.get("offsetLeft"), this.get("offsetTop")));
}
/**
  Sets the widget's position to (+x, +y) relative to the upper left hand corner of its parent container
  @param {Number} x The widget's offset on x-axis
  @param {Number} y The widget's offset on y-axis
  */
wtWidget.prototype.setAbsolutePosition = function(x, y)
{
	this.setStyle("position", "absolute");
	this.setStyle("left", x+"px");
	this.setStyle("top", y+"px");
	this.emit("Move", new wt2DPoint(x, y));
}
/**
  Gets the widget's current position relative to the upper left hand corner of its parent container <br/>
  @returns "x": current x-axis position, "y": current y-axis position
  */
wtWidget.prototype.getAbsolutePosition = function()
{
	var domNode = $_(this);
	if (!domNode) return;
	return {"x" : parseInt(domNode.offsetLeft), "y" : parseInt(domNode.offsetTop)};
}
/**
  Gets the widget's current position relative to the upper left hand corner of the screen <br/>
  @returns "x": current x-axis position, "y": current y-axis position
  */
wtWidget.prototype.getScreenPosition = function()
{
	var x = 0;
	var y = 0;
	var curNode = $_(this);
	while(curNode != null)
	{
		if (isInteger(curNode.offsetLeft) && isInteger(curNode.scrollLeft))
			x += curNode.offsetLeft - curNode.scrollLeft;
		if (isInteger(curNode.offsetTop) && isInteger(curNode.scrollTop))
			y += curNode.offsetTop - curNode.scrollTop;
		try
		{
			if (curNode.offsetParent)
				true;
		}
		catch(e)
		{
			return;
		}
		curNode = curNode.offsetParent;
	}
	if (! isMSIE())
	{
		x -= window.scrollX;
		y -= window.scrollY;
	}
	return {"x":x, "y":y};
}
/**
  Sets the widget's position to (+x, +y) relative to it's current position <br/>
  @param {Number} x The widget's offset on x-axis
  @param {Number} y The widget's offset on y-axis
  */
wtWidget.prototype.setPosition = function(x, y)
{
	var domNode = $_(this);
	domNode.style.position = "absolute";
	domNode.style.left = domNode.style.top = domNode.style.right = domNode.style.bottom = "";
	domNode.style.left = domNode.offsetLeft + x + "px";
	domNode.style.top = domNode.offsetTop + y + "px";
}
/**
  Set the widget's size
  @param {String} _width The widget's width as a CSS length quantity
  @param {String} _height The widget's height as a CSS height quantity
  */
wtWidget.prototype.setSize = function(_width, _height)
{
	var domNode = $_(this);
	domNode.style.height = dimension(_height);
	domNode.style.width = dimension(_width);
}
/**
  Sets the widget's visibility<br/><br/>
  This function differs from wtWidget.setDisplay() in which an invisible widget would still occupy space
  @param {Boolean} yes Whether the widget should be visible or not
  @see #setDisplay
  */
wtWidget.prototype.setVisible = function(yes){$_(this).style.visibility = yes ? "visible" : "hidden";}
/**
  Sets whether to display the widget or not<br/><br/>
  This function differs from wtWidget.setVisible() in which an non-displayed widget would not occupy space
  @param {Boolean} yes Whether the widget should be displayed or not
  @see #setVisible
  */
wtWidget.prototype.setDisplay = function(yes)
{
	$_(this).style.display = yes ? "" : "none";
}
/**
  Sets the alpha transparency of the widget
  @param {Number} opacity The opacity of the widget in the range [0.0, 1.0], with 0.0 meaning completely transparent and 1.0 meaning 
  completely opaque
  */
wtWidget.prototype.setAlpha = function(opacity)
{
	var domNode = $_(this);
	if (isMSIE())
	{
		if (domNode.currentStyle.hasLayout == false)
			throw "wtWidget::setAlpha(): Cannot set transparency on widget without a layout on IE!";
		if (opacity == 1.0)
			domNode.filters.item("DXImageTransform.Microsoft.Alpha").enabled = false;
		else
		{
			domNode.filters.item("DXImageTransform.Microsoft.Alpha").enabled = true;
			domNode.filters.item("DXImageTransform.Microsoft.Alpha").opacity = opacity * 100;
		}
	}
	else
		domNode.style.opacity = opacity;
}
/**
  Sets whether the widget should be draggable
  @param {Boolean} yes The widget should be draggable or not
  */
wtWidget.prototype.setDraggable = function(yes)
{
	
	var domNode = $_(this);
	if (yes)
	{
		if (domNode.style.position != "absolute")
		{
			throw "setDraggable(): Widget to set draggable must be absolutely positioned";
		}
		domNode.dragging = false;
		
		this.connect("set_dragging", "MouseDown", this, "SetDragging");
		
	}
	else
		this.disconnect("set_dragging", "MouseDown");
}
/**
  Sets the bounding area at which the widget can be dragged by the mouse cursor
  @param {Number} leftLimit The left side of the bounding box
  @param {Number} topLimit The top side of the bounding box
  @param {Number} rightLimit The right side of the bounding box
  @param {Number} bottomLimit The bottom side of the bounding box
  */
wtWidget.prototype.setDragArea = function(leftLimit, topLimit, rightLimit, bottomLimit)
{
	var domNode = $_(this);
	domNode.dragArea = {};
	domNode.dragArea.leftLimit = leftLimit;
	domNode.dragArea.topLimit = topLimit;
	domNode.dragArea.rightLimit = rightLimit;
	domNode.dragArea.bottomLimit = bottomLimit;
}
/**
  Unsets the bounding area for dragging to the default behavior at which the widget can be dragged as long as the mouse
  cursor is positioned over the widget
  */
wtWidget.prototype.unsetDragArea = function()
{
	var domNode = $_(this);
	domNode.dragArea = undefined;
}
/**
  Sets the widget to selectable or not<br/><br/>
  Note that this function is bugged in Internet Explorer, in which an "unselectable" widget can still be selected by 
  dragging over a larger area or by draggable over irrelevant widgets
  This issue is not likely to be solved since it is a bug in Internet Explorer
  @param {Boolean} yes Whether the widget is selectable or not
  */
wtWidget.prototype.setSelectable = function(yes)
{
	var domNode = $_(this);
	if (navigator.userAgent.search("MSIE") != -1)
	{
		domNode.setAttribute("UNSELECTABLE", (yes ? "off" : "on"));
		for(var i=0;i<domNode.childNodes.length;i++)
		{
			if (domNode.childNodes.item(i).setSelectable)
				domNode.childNodes.item(i).setSelectable(yes);
		}
	}
	else
	{
		domNode.style.MozUserSelect = yes ? "" : "none";
	}
	domNode.style.cursor = yes ? "" : "default";
}
/**
  Sets the widget to be enabled or not.<br/><br/>
  This general setEnabled() function only works reliably in Internet Explorer
  due to a layout bug in the GEcko engine
  If you need to use setEnabled() in your own widget classes, it is advisable 
  to override this function unless you're sure the default implementation works <br/>
  @param {Boolean} yes Whether the widget is enabled or not
  */
wtWidget.prototype.setEnabled = function(yes)
{
	var domNode = $_(this);
	domNode.wtDisabled = !yes;
	if (domNode.coverBlock == undefined)
	{
		domNode.coverBlock = new wtImage(this, "images/1ptrans.gif");
		$_(domNode.coverBlock).wtDependency = this.toString();
	}
	var coverBlock = domNode.coverBlock;
	if (yes)
	{
		coverBlock.setDisplay(false);
	}
	else
	{
		if ($_(coverBlock).parentNode)
			$_(coverBlock).parentNode.removeChild($_(coverBlock));
		domNode.parentNode.appendChild($_(coverBlock));
		coverBlock.setAbsolutePosition(domNode.offsetLeft, domNode.offsetTop);
		coverBlock.setSize(domNode.offsetWidth, domNode.offsetHeight);
		coverBlock.setLevel(parseInt(domNode.style.zIndex) + 1);
		coverBlock.setDisplay(true);
	}
}
/**
  Tells whether the widget is currently enabled or not<br/><br/>
  You may want to override this operation as well if you have overriden setEnabled() in your 
  custom widget
  @return Whether the widget is currently enabled or not
  @type Boolean
  */
wtWidget.prototype.isEnabled = function()
{
	return !($_(this).wtDisabled);
}
/**
  Tells whether a coordiate is inside the rectangular bounding box of the widget <br/>
  @param {Number} x The position on x-axis
  @param {Number} y The position on y-axis
  @return Whether the coordinate is inside this widget or not
  @type Boolean
  */
wtWidget.prototype.isInside = function(x, y)
{
	var domNode = $_(this);
	var myCoords = this.getScreenPosition();
	try
	{
		if (myCoords.x)
			true;
	}
	catch(e)
	{
		return false;
	}
	var xMin = myCoords.x;
	var yMin = myCoords.y;
	var xMax = parseInt(xMin) + parseInt(domNode.offsetWidth);
	var yMax = parseInt(yMin) + parseInt(domNode.offsetHeight);
	if (x >= xMin && x <= xMax && y >= yMin && y <= yMax)
		return true;
	return false;
}
/**
  Destroys the widget
  */
wtWidget.prototype.removeSelf = function()
{
	if ($_(this).parentNode)
		$_(this).parentNode.removeChild($_(this));
}
/**
  Clears the contents of the widget.
  */
wtWidget.prototype.clearAll = function()
{
	var domNode = $_(this);
	while(domNode.childNodes.length)
	{
		var node = domNode.childNodes.item(0);
		if (_$(node) instanceof wtWidget)
			_$(node).removeSelf();
		else
			node.parentNode.removeChild(node);
	}
}
/**
  Sets the z-axis position of the widget. The z-axis position is used for determining the overlapping order of widgets.
  The large the z-axis position, the nearer the widget is to the user.
  @param {Number} level The widget's z-axis position
  */
wtWidget.prototype.setLevel = function(level)
{
	if (_$(this.get("parentNode")) instanceof wtCanvas && level == 0)
	{
		this.get("style").zIndex = 1;
		return;
	}
	$_(this).style.zIndex = level;
}
/**
  Adds a wtWidget inside this widget
  @param {wtWidget|String} obj The wtWidget to be added. Alternatively, you may add a string to be displayed inside the widget.
  @return The widget added
  @type wtWidget
  */
wtWidget.prototype.addWidget = function(obj)
{
	var domNode = $_(this);
	if (!isDOMNode(obj))
	{
		if (typeof(obj) == "string")
		{
			var strArray = obj.split("\n");
			var lastWidget;
			for(var i=0;i<strArray.length;i++)
			{
				if (strArray[i].length == 0 && i == strArray.length -1) continue;
				domNode.appendChild(document.createTextNode(strArray[i]));
				if (obj.indexOf("\n") != -1)
					lastWidget = new wtWidget(this, "br");
			}
			return lastWidget;
		}
		else if (! $_(obj))
		{
			throw "wtWidget::addWidget(): Object must be managed by WT Toolkit";
		}
		else
		{
			domNode.appendChild($_(obj));
			return obj;
		}
	}
	else
		throw "Adding raw DOM nodes is no longer supported";
}
/**
  @private
  */
wtWidget.prototype.dragSlot = function(myself, evt, source)
{
	var widget = $_(myself);
	if (widget.dragging)
	{
		if (isMSIE())
			widget.style.margin = "0px 0px 0px 0px";
		var x = mouse.x;
		var y = mouse.y;
		myself.setAbsolutePosition(widget.offsetLeft + x - widget.prevX, widget.offsetTop + y - widget.prevY);
		widget.prevX = x;
		widget.prevY = y;
	}
}
/**
  @private
  */
wtWidget.prototype.setDraggingSlot = function(myself, evt, source)
{
	if (evt)
	{
		if (isMSIE() && evt.button != 1)
			return;
		else if (! isMSIE() && evt.button != 0)
			return;
	}
	var widget = $_(myself);
	if (widget.dragArea != undefined)
	{
		var widgetCoordinate = myself.getScreenPosition();
		var leftLimit = widgetCoordinate.x + widget.dragArea.leftLimit;
		var rightLimit = widgetCoordinate.x + widget.dragArea.rightLimit;
		var topLimit = widgetCoordinate.y + widget.dragArea.topLimit;
		var bottomLimit = widgetCoordinate.y + widget.dragArea.bottomLimit;
		if (mouse.x < leftLimit || mouse.x > rightLimit)
			return;
		if (mouse.y < topLimit || mouse.y > bottomLimit)
			return;
	}
	widget.dragging = true; 
	window.mouse.connect(myself.toString(), "MouseUp", myself, "UnsetDragging");
	window.mouse.connect(myself.toString(), "MouseMove", myself, "Drag");
	widget.prevX = mouse.x; 
	widget.prevY = mouse.y;
	myself.emit("DragStart", evt);
}
/**
  @private
  */
wtWidget.prototype.unsetDraggingSlot = function(myself, evt, source)
{
	var widget = $_(myself);
	widget.dragging = false;
	window.mouse.disconnect(myself.toString(), "MouseUp");
	window.mouse.disconnect(myself.toString(), "MouseMove");
	myself.emit("DragEnd", evt);
}
/**
  Links a DOM object's event hook (e.g. "onclick") to a wtObject signal name
  @param {String} signalName wtObject signal name
  @param {String} eventName DOM object event hook name
  */
wtWidget.prototype.linkSignal = function(signalName, eventName)
{
	var sig = $_(this).wtSignals;
	if (sig == undefined)
	{
		$_(this).wtSignals = {};
		sig = $_(this).wtSignals;
	}
	if (sig[signalName] == undefined)
		sig[signalName] = {};

	// generate the handler function for converting events into signals 
	$_(this)[eventName] = function()
	{
		// first, which event are we going to get?
		var evt;
		if (navigator.userAgent.search("MSIE") != -1)
			evt = window.event;
		else
			evt = arguments[0];
		try
		{
			if (_$(this))
				true;
		}
		catch(e){return;}
		_$(this).emit(signalName, evt);
	}
}
/**
  Tells if this widget is an ancenstor of another widget in the DOM tree
  @param {wtWidget} widget The other widget
  @returns {Boolean} Whether this widget is an ancenstor of the other widget or not
  */
wtWidget.prototype.isAncestorOf = function(widget)
{
	var curNode = $_(widget).parentNode;
	while(curNode)
	{
		if (curNode == $_(this))
			return true;
		curNode = curNode.parentNode;
	}
	return false;
}
/**
  Gets a CSS style attribute value
  @param {String} name CSS style name
  */
wtWidget.prototype.getStyle = function(name)
{
	return this.get("style")[name];
}
/**
  Sets a CSS style attribute value
  @param {String} name CSS style name
  @param {String} value CSS style value
  */
wtWidget.prototype.setStyle = function(name, value)
{
	this.get("style")[name] = value;
}
// }}}
// {{{ wtShadowWidget - a container widget that adds a rectangular soft shadow under its contents
/**
  Constructs a rectangular container with soft drop shadows
  @param {wtWidget} _parent The parent container for adding this widget to. Can also be a DOM node or null.
  @class This widget is a container that adds a soft drop shadow around the rectangular bounding box around its contents
  @constructor
  */
var wtShadowWidget = function(_parent)
{
	if (arguments.length < 1)
		return;

	// construct the basic widget
	this.base = wtWidget;
	this.base(_parent, "table");

	// determine the shadow size
	var _shadowSize = 10;
	if (arguments.length > 1)
		_shadowSize = arguments[1];
	if (_shadowSize > 10 || _shadowSize < 0)
		_shadowSize = 10;
	
	$_(this).className += " wtShadowWidget";
	$_(this).cellPadding = $_(this).border = 0;
	$_(this).cellSpacing = 0;

	var _tbody = new wtWidget(this, "tbody");
	var _row1 = new wtWidget(_tbody, "tr");
	var _row2 = new wtWidget(_tbody, "tr");
	var _contentCell = new wtWidget(_row1, "td");
	$_(this).contentCell = _contentCell;
	var _rightShadow = new wtWidget(_row1, "td");
	$_(_rightShadow).style.width = _shadowSize + "px";
	var _bottomShadow = new wtWidget(_row2, "td");
	$_(_bottomShadow).style.height = _shadowSize + "px";
	var _cornerShadow = new wtWidget(_row2, "td");
	$_(_cornerShadow).style.width = $_(_cornerShadow).style.height = _shadowSize + "px";

	if (isMSIE())
	{
		$_(_cornerShadow).style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='images/CornerShadow.png',sizingMethod='scale')";

		var rl = new wtWidget(_bottomShadow, "table");
		$_(rl).width = "100%";
		$_(rl).height = "100%";
		$_(rl).border = 0;
		$_(rl).cellSpacing = $_(rl).cellPadding = 0;
		var rbody = new wtWidget(rl, "tbody");
		var rr = new wtWidget(rbody, "tr");
		var rspace = new wtWidget(rr, "td");
		var spacer = new wtImage(rspace, "images/1ptrans.gif");
		$_(spacer).height = $_(spacer).width = parseInt(_shadowSize/2) + "px";
		var rshadow = new wtWidget(rr, "td");
		$_(rshadow).style.width = "100%";
		$_(rshadow).style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='images/BottomShadow.png',sizingMethod='scale')";

		var cl = new wtWidget(_rightShadow, "table");
		$_(cl).style.position = "absolute";
		$_(cl).width = $_(cl).height = "100%";
		$_(cl).border = $_(cl).cellSpacing = $_(cl).cellPadding = 0;
		var cbody = new wtWidget(cl, "tbody");
		$_(cbody).height = "100%";
		var cr = new wtWidget(cbody, "tr");
		var cspace = new wtWidget(cr, "td");
		var csr = new wtWidget(cbody, "tr");
		var cshadow = new wtWidget(csr, "td");
		$_(cshadow).style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='images/RightShadow.png',sizingMethod='scale')";
		$_(cshadow).width = "100%";
		$_(cshadow).height = "100%";

		// IE S-U-C-K-S!!
		// no native translucent PNG support means I have to use wtImage + polling for positioning
		// which wastes a hell lot of CPU time and the output isn't 100% correct!!
		if (isMSIE() && window.shadowPollHack == undefined)
		{
			window.shadowMap = {};
			window.shadowPollHack = function()
			{
				for(var i in shadowMap)
				{
					var cl = shadowMap[i];
					if (! $_(cl))
					{
						delete shadowMap[i];
						continue;
					}
					if ($_(cl).offsetParent 
							&& $_(cl).offsetWidth > 0
							&& $_(cl).offsetHeight != ($_(cl).offsetParent.clientHeight -1) 
							&& $_(cl).offsetParent.clientHeight)
						$_(cl).style.height = ($_(cl).offsetParent.clientHeight -1) + "px";
				}
			}
			setInterval(shadowPollHack, 500);
		}

		if (isMSIE())
			shadowMap[cl.toString()] = cl;
	}
	else
	{
		if (_shadowSize > 5)
		{
			$_(_cornerShadow).style.backgroundImage = "url('images/CornerShadow.png')";
			$_(_rightShadow).style.backgroundImage = "url('images/RightShadow.png')";
			$_(_bottomShadow).style.backgroundImage = "url('images/BottomShadow.png')";
		}
		else
		{
			$_(_cornerShadow).style.backgroundImage = "url('images/CornerShadowS.png')";
			$_(_rightShadow).style.backgroundImage = "url('images/RightShadowS.png')";
			$_(_bottomShadow).style.backgroundImage = "url('images/BottomShadowS.png')";
		}
		$_(_rightShadow).style.backgroundPosition = "0px " + parseInt(_shadowSize/2) + "px";
		$_(_rightShadow).style.backgroundRepeat = "no-repeat";
		$_(_bottomShadow).style.backgroundPosition = parseInt(_shadowSize/2) + "px 0px";
		$_(_bottomShadow).style.backgroundRepeat = "no-repeat";
	}
}
wtShadowWidget.prototype = new wtWidget;
/**
  Adds a widget inside the drop shadow container
  @param {wtWidget} widget The widget for adding drop shadow to
  */
wtShadowWidget.prototype.addWidget = function(widget)
{
	if (!$_(this).contentCell)
		$_(this).appendChild($_(widget));
	else
		return $_(this).contentCell.addWidget(widget);
}
// }}}
// {{{ wtImage - generic image object
// returns an image object, supports transparent PNGs in IE too!
/**
  Constructs a raster image object <br/>
  @class A raster image object. This class differs from the simple &lt;img&gt; tag that it can be used to display transparent .PNG in Internet Explorer 6
  @param {wtWidget} _parent The parent container for adding this widget to. Can also be a DOM node or null.
  @param {String} _url The URL to the raster image file.
  @constructor
  */
var wtImage = function(_parent, _url)
{
	if (arguments.length < 2)
		return;
	this.base = wtWidget;
	this.base(_parent, "img");

	if (isMSIE())
		$_(this).style.filter = "progid:DXImageTransform.Microsoft.Alpha(opacity=100)";
	$_(this).border = 0;
	$_(this).className += " wtImage";
	this.setSelectable(false);
	if (isMSIE() && _url.search(new RegExp("\\.png(\\?.*)?$", "i")) != -1)
	{
		$_(this).transformed = false;
		var alias = this;
		var onloadhandler = function()
		{
			if (this.transformed)
				return;
			var transform = function()
			{
				if (!$_(alias))
					return;
				$_(alias).transformed = true;
				if ((!alias.get("style").width) && (!alias.get("style").height))
				{
					$_(alias).style.width = $_(alias).offsetWidth+"px";
					$_(alias).style.height = $_(alias).offsetHeight+"px";
				}
				$_(alias).src = "images/1ptrans.gif";
				var newfilter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + _url + "',sizingMethod='scale')";
				$_(alias).style.filter = newfilter;
			}
			setTimeout(transform, 0);
		}
		$_(this).onload = onloadhandler;
		$_(this).src = _url;
	}
	else
		$_(this).src = _url;
}
wtImage.prototype = new wtWidget
// }}}
// {{{ wtView - a fixed size container with automatic scroll bars and optional borders
/**
  Constructs a view container
  @class A view container in WT Toolkit is a fixed size container with automatic scroll bars and optional borders
  It is typically used as a part of more sophisticated widget containes, e.g.&nbsp;a wtWindow
  @param {wtWidget} _parent The parent container for adding this widget to. Can also be a DOM node or null.
  @param {String} _width The widget's width as a CSS length quantity.
  @param {String} _height The widget's height as a CSS height quantity.
  @see wtWindow
  @constructor
  */
var wtView = function(_parent, _width, _height)
{
	if (arguments.length < 3)
		return;

	this.base = wtWidget;
	this.base(_parent, "div");
	this.setSize(_width, _height);
	$_(this).className += " wtView";
	$_(this).style.overflow = "auto";
	$_(this).align = "center";
}
wtView.prototype = new wtWidget;
/**
  Gives the view widget a solid border with a color defined by the programmer
  @param {String} color The border's color, as a CSS color string
  */
wtView.prototype.setBorder = function(color)
{
	$_(this).style.border = "solid 1px " + color;
}
/**
  Removes the solid border around the view widget
  */
wtView.prototype.unsetBorder = function()
{
	$_(this).style.border = "none";
}
// }}}
// {{{ wtWindow - a draggable container widget with a title, a wtView area and soft drop shadow
/**
  Constructs a window-like container with a fixed width and fixed height.
  @class A wtWindow is a draggable container widget with a title bar (empty by default), a wtView container area and soft drop shadow
  @param {wtWidget|wtWindowManager|DOM_Node} _parent The parent container for the window. 
  This can be another wtWidget, a wtWindowManager, or a DOM Node like document.body.
  @param {String} _width The widget's width as a CSS length quantity.
  @param {String} _height The widget's height as a CSS height quantity.
  @see wtWindowManager
  @see wtView
  @constructor
  */
var wtWindow = function(_parent, _width, _height)
{
	if (arguments.length < 3)
		return;

	this.base = wtShadowWidget;
	this.base(_parent);

	$_(this).className += " wtWindow";
	$_(this).modal = false;
	$_(this).style.position = "absolute";

	var _winbox = new wtWidget(this, "table");
	$_(this).windowBox = _winbox;
	$_($_(this).windowBox).className += " WindowBackground";
	$_($_(this).windowBox).cellSpacing = 1;
	$_($_(this).windowBox).border = 0;
	var _tb = new wtWidget(_winbox, "tbody");

	var _titleRow = new wtWidget(_tb, "tr");
	var _contentRow = new wtWidget(_tb, "tr");

	var tc = new wtWidget(_titleRow, "td");
	var titleLayout = new wtRowLayout(tc, "100%");
	var _titleCell = titleLayout.addWidget("");
	$_(_titleCell).className += " WindowTitle";
	_titleCell.setSelectable(false);
	$_(this).titleCell = _titleCell;
	_titleCell.setSize("100%", "");
	var _contentCell = new wtWidget(_contentRow, "td");
	$_(this).contentCell = _contentCell;
	var _contentBlock = new wtView(_contentCell, _width, _height);
	$_(_contentCell).className += " WindowContent";
	_contentCell.set("colSpan", 2);
	$_(this).contentBlock = _contentBlock;
	this.setSlot("Close", this.closeSlot);

	var closeCell = titleLayout.addWidget("X");
	this.set("closeCell", closeCell);
	closeCell.set("align", "right");
	$_(closeCell).className += " WindowClose";
	closeCell.connect("close_window", "Click", this, "Close");
	closeCell.setDisplay(false);
	
	var _coverBlock = new wtImage(document.body, "images/WindowCover.png");
	$_(_coverBlock).wtDependency =  this.toString();
	$_(this).coverBlock = _coverBlock;
	_coverBlock.setAbsolutePosition(500, 500);
	$_(_coverBlock).style.display = "none";

	var _randint = parseInt(Math.random() * 100000);
	$_(this).titleCell.connect("window_set_dragging", "MouseDown", this, "SetDragging");

	var activeCoverBlockSlot = function(myself, evt, source)
	{
		myself.emit("Click", evt);
	}
	this.setSlot("ActivateCover", activeCoverBlockSlot);
	_coverBlock.connect("activate_cover", "Click", this, "ActivateCover");

	this.setSize(_width, _height);
}
wtWindow.prototype = new wtShadowWidget;
/**
  @private
  */
wtWindow.prototype.closeSlot = function(myself, evt, source)
{
	myself.removeSelf();
}
/**
  @private
  */
wtWindow.prototype._wtWidget_setLevel = wtWidget.prototype.setLevel;
/**
  Sets the title of the window. The title is normally a string, but it can be a wtWidget also.
  @param {String|wtWidget} title The new title
  */
wtWindow.prototype.setTitle = function(title)
{
	$_(this).titleCell.clearAll();
	$_(this).titleCell.addWidget(title);
}
/**
  Sets whether the window is draggable or not.
  @param {Boolean} yes The widget should be draggable or not
  */
wtWindow.prototype.setDraggable = function(yes)
{
	if (yes)
		$_(this).titleCell.connect("window_set_dragging", "MouseDown", _$(this), "SetDragging");
	else
		$_(this).titleCell.disconnect("window_set_dragging", "MouseDown");
}
/**
  @private
  */
wtWindow.prototype._wtShadowWidget_addWidget = wtShadowWidget.prototype.addWidget;
/**
  Adds a wtWidget inside this window
  @param {wtWidget|String} widget The wtWidget to be added. Alternatively, you may add a string to be displayed inside the widget.
  @return The widget added
  @type wtWidget
  */
wtWindow.prototype.addWidget = function(widget)
{
	if (!$_(this).contentBlock)
		this._wtShadowWidget_addWidget(widget);
	else
		return $_(this).contentBlock.addWidget(widget);
}
/**
  @private
  */
wtWindow.prototype._wtShadowWidget_setSize = wtShadowWidget.prototype.setSize;
/**
  Sets the size of the window
  @param {String} _width The widget's width as a CSS length quantity.
  @param {String} _height The widget's height as a CSS height quantity.
  */
wtWindow.prototype.setSize = function(_width, _height)
{
	this._wtShadowWidget_setSize(_width + 11, "");
	$_(this).contentBlock.setSize(_width, _height);
}
/**
  Sets whether the window is enabled or not. A disabled window appears to be transparent and cannot be dragged. 
  A disabled window added under a wtWindowManager, however, can be re-enabled if the user clicks on it. <br/>
  @param {Boolean} yes Whether the widget is enabled or not
  */
wtWindow.prototype.setEnabled = function(yes)
{
	$_(this).wtDisabled = !yes;
	if (yes)
	{
		$_($_(this).coverBlock).style.display = "none";
		this.setAlpha(1.0);
		if (isMSIE())
		{
			var selectBoxes = $_(this).getElementsByTagName("select");
			for (var i=0;i<selectBoxes.length;i++)
				selectBoxes[i].style.visibility = "";
		}
	}
	else
	{
		$_($_(this).coverBlock).style.display = "";
		$_($_(this).coverBlock).parentNode.removeChild($_($_(this).coverBlock));
		$_(this).parentNode.appendChild($_($_(this).coverBlock));
		var _coverBlock = $_(this).coverBlock;
		_coverBlock.setLevel(parseInt($_(this).style.zIndex) + 1);
		var windowCoordinate = this.getAbsolutePosition();
		_coverBlock.setAbsolutePosition(windowCoordinate.x, windowCoordinate.y);
		_coverBlock.setSize($_($_(this).windowBox).offsetWidth, $_($_(this).windowBox).offsetHeight);
		this.setAlpha(0.5);
		if (isMSIE())
		{
			var selectBoxes = $_(this).getElementsByTagName("select");
			for (var i=0;i<selectBoxes.length;i++)
				selectBoxes[i].style.visibility = "hidden";
		}
	}
}
/**
  Tells whether the window is currently enabled or not
  @returns Whether the window is currently enabled or not
  @type Boolean
  */
wtWindow.prototype.isEnabled = function()
{
	return !(this.wtDisabled);
}
/**
  Sets the z-axis position of the window. The z-axis position is used for determining the overlapping order of widgets.
  @param {Number} nL The z-axis position of the window
  */
wtWindow.prototype.setLevel = function(nL)
{
	this._wtWidget_setLevel(nL);
	if ($_(this).coverBlock)
		$_(this).coverBlock.setLevel(nL+1);
}
/**
  Sets the modality of the window. A modal window cannot be de-focused by a wtWindowManager when it is the topmost window.
  @param {Boolean} yes Whether the window is modal or not
 */
wtWindow.prototype.setModal = function(yes)
{
	$_(this).modal = yes ? true : false;
}
/**
  Clears the contents of the widget.<br/><br/>
  This resets any attributes of the contentCell as well, such as align and CSS styles. The reset is done due to
  the need to circumvent an Internet Explorer bug.
  */
wtWindow.prototype.clearAll = function()
{
	var newContentBlock = new wtView(this.get("contentCell"), this.get("contentBlock").get("offsetWidth"), 
			this.get("contentBlock").get("offsetHeight"));
	this.get("contentBlock").removeSelf();
	this.set("contentBlock", newContentBlock);
}
/**
  Puts the window at the center of the browser's display area. <br/><br/>
  This is usually not what you actually want, because the center of the browser's display area is usually not 
  what the user think the "center". You may want to use ucenter() instead. <br/>
  @see #ucenter
  */
wtWindow.prototype.center = function()
{
	var cd = getClientDimensions();
	var p_x = (cd.width - this.offsetWidth)/2;
	var p_y = (cd.height - this.offsetHeight)/2;
	if (p_x < 0) p_x = 0;
	if (p_y < 0) p_y = 0;
	this.setAbsolutePosition(p_x, p_y);
}
/**
  Puts the window at the upper center of the browser's display area. <br/>
  @see #center
  */
wtWindow.prototype.ucenter = function()
{
	var cd = getClientDimensions();
	var p_x = (cd.width - $_(this).offsetWidth)/2;
	var p_y = (cd.height - $_(this).offsetHeight)/3;
	if (p_x < 0) p_x = 0;
	if (p_y < 0) p_y = 0;
	this.setAbsolutePosition(p_x, p_y);
}
/**
  @private
  */
wtWindow.prototype._wtShadowWidget_removeSelf = wtShadowWidget.prototype.removeSelf;
/**
  Destroys the window.
  */
wtWindow.prototype.removeSelf = function()
{
	if (this.get("windowManager"))	// check whether managed by a wtWindowManager or not
	{
		_$($_(this.get("windowManager"))).removeWindow(this);
		return;
	}
	this._wtShadowWidget_removeSelf();
}
/**
  Enables or disables the "X" icon at the top right corner
  of the window.
  @param {Boolean} yes Whether the "X" icon should appear or not.
  */
wtWindow.prototype.enableCloseIcon = function(yes)
{
	this.get("closeCell").setDisplay(yes);
}
// }}}
// {{{ wtModalWindow - modal wtWindow
/**
  Constructs a modal window.
  @class A wtModalwindow is similar to wtWindow, except that it is created modal by default. This means 
  it cannot be defocused by a wtWindowManager when the user clicks on the other windows in the background.
  @param {wtWidget|wtWindowManager|DOM Node} The parent container for the window.
  @param {Number} width The fixed width in pixels
  @param {Number} height The fixed height in pixels
  @see wtWindowManager
  @constructor
  */
var wtModalWindow = function(parentWidget, width, height)
{
	if (arguments.length < 3)
		return;

	var p = {"x":0, "y":0};
	if (!isDOMNode(parentWidget))
	{
		if ($_(parentWidget).windowList && $_(parentWidget).windowList.prevNode.data)
		{
			p = $_(parentWidget).windowList.prevNode.data.getAbsolutePosition();
			p.x -= 10;
			p.y -= 10;
		}
	}

	this.base = wtWindow;
	this.base(parentWidget, width, height);
	this.setModal(true);
	this.setAbsolutePosition(p.x, p.y);
}
wtModalWindow.prototype = new wtWindow;
// }}}
// {{{ wtButton - horizontal container widget that changes color on mouse over
/**
  Constructs a button.
  @class This class provides you a typical image-based button with graphical effects.
  @param {wtWidget|DOM_Node} _parent The parent container
  @param {String|wtWidget} _child The content of the button, can be a string or a small widget
  @constructor
  */
var wtButton = function(_parent, _child)
{
	if (arguments.length < 2)
		return;

	this.base = wtWidget;
	this.base(_parent, "table");
	$_(this).cellSpacing = $_(this).border = $_(this).cellPadding = 0;
	$_(this).className += " wtButton";
	var _tbody = new wtWidget(this, "tbody");
	var _tr = new wtWidget(_tbody, "tr");
	var _leftCell = new wtWidget(_tr, "td");
	var _centerCell = new wtWidget(_tr, "td");
	$_(_centerCell).className += " wtButton";
	var _rightCell = new wtWidget(_tr, "td");

	$_(_leftCell).style.width = $_(_rightCell).style.width = "15px";
	$_(_leftCell).style.height = $_(_rightCell).style.height = $_(_centerCell).style.height = "20px";
	$_(_centerCell).style.overflow = "hidden";
	if (!isMSIE())
	{
		$_(_leftCell).style.backgroundImage = "url(images/ButtonInactiveLeft.png)";
		$_(_centerCell).style.backgroundImage = "url(images/ButtonInactiveCenter.png)";
		$_(_centerCell).style.backgroundRepeat = "repeat-x";
		$_(_rightCell).style.backgroundImage = "url(images/ButtonInactiveRight.png)";
		var _activate = function(widget, evt)
		{
			if ($_(widget).wtDisabled) return;
			$_($_(widget).leftCell).style.backgroundImage = "url(images/ButtonActiveLeft.png)";
			$_($_(widget).centerCell).style.backgroundImage = "url(images/ButtonActiveCenter.png)";
			$_($_(widget).rightCell).style.backgroundImage = "url(images/ButtonActiveRight.png)";
		}
		var _deactivate = function(widget, evt)
		{
			if ($_(widget).wtDisabled) return;
			$_($_(widget).leftCell).style.backgroundImage = "url(images/ButtonInactiveLeft.png)";
			$_($_(widget).centerCell).style.backgroundImage = "url(images/ButtonInactiveCenter.png)";
			$_($_(widget).rightCell).style.backgroundImage = "url(images/ButtonInactiveRight.png)";
		}
		this.setSlot("Activate", _activate);
		this.setSlot("Deactivate", _deactivate);
		this.connect("button_activate", "MouseOver", this, "Activate");
		this.connect("button_deactivate", "MouseOut", this, "Deactivate");
	}
	else
	{
		$_(_leftCell).style.filter += 
			" progid:DXImageTransform.Microsoft.AlphaImageLoader(src='images/ButtonInactiveLeft.png',sizingMethod='scale')";
		$_(_centerCell).style.filter += 
			" progid:DXImageTransform.Microsoft.AlphaImageLoader(src='images/ButtonInactiveCenter.png',sizingMethod='scale')";
		$_(_centerCell).style.backgroundRepeat = "repeat-x";
		$_(_rightCell).style.filter += 
			" progid:DXImageTransform.Microsoft.AlphaImageLoader(src='images/ButtonInactiveRight.png',sizingMethod='scale')";
		var _deactivate = function(widget, evt)
		{
			if ($_(widget).wtDisabled) return;
			$_($_(widget).leftCell).filters.item("DXImageTransform.Microsoft.AlphaImageLoader").src = "images/ButtonInactiveLeft.png";
			$_($_(widget).centerCell).filters.item("DXImageTransform.Microsoft.AlphaImageLoader").src = "images/ButtonInactiveCenter.png";
			$_($_(widget).rightCell).filters.item("DXImageTransform.Microsoft.AlphaImageLoader").src = "images/ButtonInactiveRight.png";
		}
		var _activate = function(widget, evt)
		{
			if ($_(widget).wtDisabled) return;
			$_($_(widget).leftCell).filters.item("DXImageTransform.Microsoft.AlphaImageLoader").src = "images/ButtonActiveLeft.png";
			$_($_(widget).centerCell).filters.item("DXImageTransform.Microsoft.AlphaImageLoader").src = "images/ButtonActiveCenter.png";
			$_($_(widget).rightCell).filters.item("DXImageTransform.Microsoft.AlphaImageLoader").src = "images/ButtonActiveRight.png";
		}
		this.setSlot("Activate", _activate);
		this.setSlot("Deactivate", _deactivate);
		this.connect("button_activate", "MouseOver", this, "Activate");
		this.connect("button_deactivate", "MouseOut", this, "Deactivate");
	}
	var _mousedown = function(widget, evt)
	{
		if ($_(widget).wtDisabled) return;
		if (!isMSIE())		// will look ugly in IE, so disabled for IE
			$_($_(widget).centerCell).style.padding = "2px 0px 0px 0px";
		$_(widget).focus();
	}
	var _mouseup = function(widget, evt)
	{
		if ($_(widget).wtDisabled) return;
		$_($_(widget).centerCell).style.padding = "0px 0px 0px 0px";
	}
	this.setSlot("Pressing", _mousedown);
	this.setSlot("Pressed", _mouseup);
	$_(this).mouseId = parseInt(Math.random() * 100000);
	this.connect("button_pressing", "MouseDown", this, "Pressing");
	this.connect("button_pressed", "MouseUp", this, "Pressed");

	$_(this).leftCell = _leftCell;
	$_(this).centerCell = _centerCell;
	$_(this).rightCell = _rightCell;
	$_(this).wtDisabled = false;
	this.setContent(_child);
	this.setSelectable(false);
}
wtButton.prototype = new wtWidget;
/**
  Sets the content of the button to be something else.
  @param {String|wtWidget} _child The new contents of the button, can be a string or a small widget
 */
wtButton.prototype.setContent = function(_child)
{
	$_(this).centerCell.clearAll();
	$_(this).centerCell.addWidget(_child);
}
/**
  Sets the click handler of the button.
  @param {Function} handler The click handler. 
  Input arguments of the handler follow the universal event handler format in WT Toolkit.
  @see wtObject#connect
 */
wtButton.prototype.setHandler = function(handler)
{
	this.setSlot("ClickHandler", handler);
	this.connect("button_click", "Click", this, "ClickHandler");
}
/**
  Removes the click handler of the button.
  */
wtButton.prototype.resetHandler = function()
{
	this.disconnect("button_click", "Click");
}
/**
  @private
  */
wtButton.prototype._wtWidget_addWidget = wtWidget.prototype.addWidget;
/**
  Adds a wtWidget inside the content cell of this button
  @param {wtWidget} _widget The wtWidget to be added. Alternatively, you may add a string to be displayed inside the button's content cell.
  @return The widget added
  @type wtWidget
  */
wtButton.prototype.addWidget = function(_widget)
{
	if (! $_(this).centerCell)
		this._wtWidget_addWidget(_widget);
	else
		return $_(this).centerCell.addWidget(_widget);
}
/**
  Sets whether the button is enabled or not. A disabled button appears grayed and is unresponsive to user events such as clicks and 
  mouse overs.
  @param {Boolean} yes Whether the button is enabled or not
  */
wtButton.prototype.setEnabled = function(yes)
{
	$_(this).wtDisabled = !yes;
	if (yes)
	{
		this.linkSignal("Click", "onclick");
		this.setAlpha(1.0);
	}
	else
	{
		$_(this).removeAttribute("onclick");
		this.setAlpha(0.5);
	}
}
/**
  Tells whether the button is currently enabled or not
  @returns Whether the button is currently enabled or not
  @type Boolean
  */
wtButton.prototype.isEnabled = function()
{
	return !(this.wtDisabled);
}
// }}}
// {{{ wtAnchor - hyperlink-like widget that can be used to call javascript as well
/**
  Constructs a text-only link which can be used to invoke event handlers or act as simple hyperlinks.
  @class A wtAnchor can be used in two ways: <br/><br/>
  It can be used as a traditional HTML anchor (i.e.&nbsp;a hyperlink) by setting a href attribute to it via 
  <a href="wtAnchor.html#setHref">setHref()</a><br/>
  Or, it can be used as a text-only button by setting an event handler to it via 
  <a href="wtAnchor.html#setHandler">setHandler()</a>
  @param {wtWidget|DOM_Node} _parent The parent container for adding this widget to. Can also be a DOM node or null.
  @param {String} _desc The caption text of the anchor
  @constructor
  */
var wtAnchor = function(_parent, _desc)
{
	if (arguments.length < 2)
		return;

	this.base = wtWidget;
	this.base(_parent, "a");
	$_(this).className += " wtAnchor AnchorInactive";

	this.addWidget(_desc);
	$_(this).removeAttribute("href");

	var activateSlot = function(widget, evt, source)
	{
		if ($_(widget).wtDisabled) return;
		$_(widget).className = $_(widget).className.replace(new RegExp("Anchor[a-zA-z0-9]+"), "AnchorActive");
	}
	var deactivateSlot = function(widget, evt, source)
	{
		if ($_(widget).wtDisabled) return;
		$_(widget).className = $_(widget).className.replace(new RegExp("Anchor[a-zA-z0-9]+"), "AnchorInactive");
	}
	var selectSlot = function(widget, evt, source)
	{
		$_(widget).className = $_(widget).className.replace(new RegExp("Anchor[a-zA-z0-9]+"), "AnchorSelected");
	}
	this.setSlot("Activate", activateSlot);
	this.setSlot("Deactivate", deactivateSlot);
	this.setSlot("Select", selectSlot);
	this.setSlot("Unselect", deactivateSlot);

	this.setSelected(false);
}
wtAnchor.prototype = new wtWidget;
/**
  @private
  */
wtAnchor.prototype.setSelected = function(yes)
{
	if (yes)
	{
		this.disconnect("anchor_activate", "MouseOver");
		this.disconnect("anchor_deactivate", "MouseOut");
		$_(this).wtSlots.Select(this, null);
	}
	else
	{
		this.connect("anchor_activate", "MouseOver", this, "Activate");
		this.connect("anchor_deactivate", "MouseOut", this, "Deactivate");
		$_(this).wtSlots.Unselect(this, null);
	}
}
/**
  Sets the href attribute of the anchor for use as a traditional hyperlink
  @param {String} href A valid URL
  */
wtAnchor.prototype.setHref = function(href)
{
	this.resetHandler();
	var before = $_(this).innerHTML;
	$_(this).href = href;
	$_(this).innerHTML = before;
}
/**
  Removes the href attribute of the anchor
  */
wtAnchor.prototype.resetHref = function()
{
	$_(this).removeAttribute("href");
}
/**
  Sets the click handler of the anchor for use as a text-only button
  @param {Function} handler The click handler.
  Input arguments of the handler follow the universal event handler format in WT Toolkit.
  @see wtObject#connect
  */
wtAnchor.prototype.setHandler = function(handler)
{
	this.resetHref();
	this.setSlot("ClickHandler", handler);
	this.connect("anchor_click", "Click", this, "ClickHandler");
}
/**
  Removes the click handler of the anchor
  */
wtAnchor.prototype.resetHandler = function()
{
	this.removeSlot("ClickHandler");
	this.disconnect("anchor_click", "Click");
}
/**
  Sets whether the anchor is enabled or not. A disabled anchor appears grayed and is unresponsive to user events such as clicks and
  mouse overs.
  @param {Boolean} yes Whether the anchor is enabled or not
  */
wtAnchor.prototype.setEnabled = function(yes)
{
	$_(this).wtDisabled = !yes;
	if (yes)
	{
		this.linkSignal("Click", "onclick");
		if ($_(this).href == undefined && $_(this).hrefCopy != undefined)
			$_(this).href = $_(this).hrefCopy;
		this.setAlpha(1.0);
	}
	else
	{
		$_(this).removeAttribute("onclick");
		$_(this).hrefCopy = $_(this).href;
		$_(this).removeAttribute("href");
		this.setAlpha(0.5);
	}
}
/**
  Tells whether the anchor is currently enabled or not
  @returns Whether the anchor is currently enabled or not
  @type Boolean
  */
wtAnchor.prototype.isEnabled = function()
{
	return !($_(this).wtDisabled);
}
// }}}
// {{{ wtSpacer - variable size inline spacer
/**
  Constructs an area of empty space with inline layout for separation purpose.
  @class An area of empty space with inline layout.
  @constructor
  @param {wtWidget|DOM_Node} _parent The parent container for adding this widget to. Can also be a DOM node or null.
  @param {String} _width The widget's width as a CSS length quantity.
  @param {String} _height The widget's height as a CSS height quantity.
  */
var wtSpacer = function(_parent, _width, _height)
{
	if (arguments.length < 3)
		return;

	this.base = wtWidget;
	this.base(_parent, "img");

	$_(this).src = "images/1ptrans.gif";
	$_(this).style.width = dimension(_width);
	$_(this).style.height = dimension(_height);
	this.setSelectable(false);
	$_(this).style.display = "inline";
}
wtSpacer.prototype = new wtWidget;
// }}}
// {{{ wtBlockSpacer - variable size block spacer
/**
  Constructs an area of empty space with block layout for separation purpose. 
  @class An area of empty space with block layout.
  @constructor
  @param {wtWidget|DOM_Node} _parent The parent container for adding this widget to. Can also be a DOM node or null.
  @param {String} _width The widget's width as a CSS length quantity.
  @param {String} _height The widget's height as a CSS height quantity.
  */
var wtBlockSpacer = function(_parent, _width, _height)
{
	if (arguments.length < 3)
		return;

	this.base = wtSpacer;
	this.base(_parent, _width, _height);
	$_(this).style.display = "block";
}
wtBlockSpacer.prototype = new wtSpacer;
// }}}
// {{{ wtRowLayout - horizontal layout container
/**
  Constructs a widget that layouts its child widgets along a row.
  @class A widget that layouts its child widgets along a row.
  @constructor
  @param {wtWidget|DOM_Node} _parent The parent container for adding this widget to. Can also be a DOM node or null.
  @param {String} _size The width of the row in a CSS length quantity. e.g. "200px", "92%", etc.
  */
var wtRowLayout = function(_parent, _size)
{
	if (arguments.length < 2)
		return;

	this.base = wtWidget;
	this.base(_parent, "table");

	$_(this).border = $_(this).cellSpacing = $_(this).cellPadding = 0;
	$_(this).className += " wtRowLayout";
	$_(this).style.width = dimension(_size);
	$_(this).contentRow = new wtWidget(new wtWidget(this, "tbody"), "tr");

	if (!isMSIE())
		$_(this).cells = $_($_(this).contentRow).cells;
}
wtRowLayout.prototype = new wtWidget;
/**
  @private
  */
wtRowLayout.prototype._wtWidget_addWidget = wtWidget.prototype.addWidget;
/**
  Adds a wtWidget as the next widget along the row
  @param {wtWidget|String} widget The widget to be added. It can be a wtWidget or a string.
  @return The table cell containing the added widget
  @type wtWidget
  */
wtRowLayout.prototype.addWidget = function(widget)
{
	if (!$_(this).contentRow)
	{
		this._wtWidget_addWidget(widget);
		return;
	}
	var newCell = new wtWidget($_(this).contentRow, "td");
	newCell.addWidget(widget);
	return newCell;
}
/**
  Adds a spacer towards the end of the row
  @param {String} _width The spacer's width as a CSS length quantity.
  @return The spacer added
  @type wtSpacer
  */
wtRowLayout.prototype.addSpacer = function(_width)
{
	var cell = new wtWidget($_(this).contentRow, "td");
	$_(cell).className += " wtRowSpacerCell";
	$_(cell).style.width = dimension(_width);
	var img = new wtImage(cell, "images/1ptrans.gif");
	img.setSize(_width, "1px");
	return cell;
}
// }}}
// {{{ wtColumnLayout - vertical layout container
/**
  Constructs a widget that layouts its child widgets along a column.
  @class A widget that layouts it schild widgets along a column.
  @constructor
  @param {wtWidget|DOM_Node} _parent The parent container for adding this widget to. Can also be a DOM node or null.
  @param {String} _width The width of the column in a CSS length quantity. e.g. "200px", "92%", etc.
  */
var wtColumnLayout = function(_parent, _width)
{
	if (arguments.length < 2)
		return;

	this.base = wtWidget;
	this.base(_parent, "table");

	$_(this).border = $_(this).cellSpacing = $_(this).cellPadding = 0;
	$_(this).className += " wtColumnLayout";
	$_(this).style.width = dimension(_width);
	if (arguments.length > 2)
		$_(this).style.height = arguments[2] + (isInteger(arguments[2]) ? "px" : "");
	$_(this).tbody = new wtWidget(this, "tbody");
}
wtColumnLayout.prototype = new wtWidget;
/**
  @private
  */
wtColumnLayout.prototype._wtWidget_addWidget = wtWidget.prototype.addWidget;
/**
  Adds a wtWidget as the next widget along the column.
  @param {wtWidget|String} widget The widget to be added. It can be a wtWidget or a string.
  @return The table cell containing the added widget
  @type wtWidget
  */
wtColumnLayout.prototype.addWidget = function(widget)
{
	if (!$_(this).tbody)
	{
		this._wtWidget_addWidget(widget);
		return;
	}
	var newRow = new wtWidget($_(this).tbody, "tr");
	var newCell = new wtWidget(newRow, "td");
	newCell.addWidget(widget);
	return newCell;
}
/**
  Adds a spacer towards the end of the column
  @param {String} _height The spacer's height as a CSS length quantity.
  @return The spacer added
  @type wtSpacer
  */
wtColumnLayout.prototype.addSpacer = function(_height)
{
	var c = new wtSpacer(this, 1, _height);
	$_(c).style.height = _height;
	return c;
}
// }}}
// {{{ wtDisplayCell - table cell with optional widget and data used in wtDisplay
/**
  Constructs a table cell, containing a widget and optionally a data value
  @class A table cell used in wtDisplay.
  @param {wtWidget|String} _widget The widget contained in the cell, can be a wtWidget or a string
  @param _value (Optional) The data value of the cell
  @constructor
  */
var wtDisplayCell = function(_widget, _value)
{
	if (arguments.length < 1)
		return;

	this.base = wtWidget;
	this.base(null, "td");
	if (isNumber(_widget))
		this.addWidget(String(_widget));
	else
		this.addWidget(_widget);
	if (_value)
		$_(this).cellValue = _value;
	$_(this).className += " wtDisplayCell";
}
wtDisplayCell.prototype = new wtWidget;
/**
  Sets the content widget of the display cell
  @param {wtWidget} widget The content widget
  */
wtDisplayCell.prototype.setContent = function(widget)
{
	this.clearAll();
	if (isString(widget) || isNumber(widget))
		$_(this).cellValue = widget;
	this.addWidget(widget);
}
/**
  Sets the data value of the display cell
  @param value The data value
  */
wtDisplayCell.prototype.setValue = function(value)
{
	$_(this).cellValue = value;
}
/**
  Tells the column index of the display cell in its parent display table
  @return The current column index of the display cell
  @type Integer
  */
wtDisplayCell.prototype.colIndex = function()
{
	if (! $_(this).parentNode) return null;
	for(var i=0;i<$_(this).parentNode.cells.length;i++)
		if ($_(this).parentNode.cells.item(i) == $_(this)) return i;
	return null;
}
// }}}
// {{{ wtDisplayRow - multiple column row used in wtDisplay
/**
  Constructs a display row used in a display table.
  @constructor
  @class A display row used in a display table.
  @param {wtDisplay} _parent The parent display table.
  */
var wtDisplayRow = function(_parent)
{
	if (arguments.length < 1)
		return;

	this.base = wtWidget;
	this.base(_parent, "tr");

	$_(this).dataColumn = 0;
}
wtDisplayRow.prototype = new wtWidget;
/**
  Tells the data value of the cell under the data column. The data column of a display row is defined by the 
  setDataColumn() function.
  @see #setDataColumn
  @return Data value of data column cell.
  */
wtDisplayRow.prototype.getValue = function()
{
	return $_(this).cells.item($_(this).dataColumn).cellValue;
}
/**
  Tells all the data values of all display cells in this display row.
  @return Data values in an array
  @type Array
  */
wtDisplayRow.prototype.getValueList = function()
{
	var retval = [];
	for(var i=0;i<$_(this).cells.length;i++)
		retval.push($_(this).cells.item(i).cellValue);
	return retval;
}
/**
  Sets the data column index. The data column index is used to determine which display cell's data value to be 
  returned in the getValue() operation.
  @param {Integer} idx Data column index
  @see #getValue
  */
wtDisplayRow.prototype.setDataColumn = function(idx)
{
	$_(this).dataColumn = idx;
}
/**
  Adds a list of widgets into the display row to be contained in a series of display cells.
  @param {Array} widgetList List of widgets to be added
  @returns The list of new display cells containing the widget list
  @type Array
  */
wtDisplayRow.prototype.addWidgetList = function(widgetList)
{
	var retval = [];
	for(var i=0;i<widgetList.length;i++)
		retval.push(this.addWidget(widgetList[i]));
	return retval;
}
/**
  @private
  */
wtDisplayRow.prototype._wtWidget_addWidget = wtWidget.prototype.addWidget;
/**
  Adds a widget towards the end of the display row.
  @param {wtWidget} widget
  @returns The new display cell containing the widget
  @type wtDisplayCell
  */
wtDisplayRow.prototype.addWidget = function(widget)
{
	var cell;
	this._wtWidget_addWidget(cell = new wtDisplayCell(widget));
	if (isString(widget) || isNumber(widget))
		cell.setValue(widget);
	return cell;
}
// }}}
// {{{ wtDisplay - tabular display with an optional caption
/**
  Constructs a tabular display with an optional caption
  @constructor
  @class A tabular display with an optional caption. Available signals: <br/>
  <ul>
  <li>Sort</li>
  </ul>
  @param {wtWidget|DOM_Node} _parent The parent container for adding this widget to. Can also be a DOM node or null.
  @param {String} _width The widget's width as a CSS length quantity.
  */
var wtDisplay = function(_parent, _width)
{
	if (arguments.length < 2)
		return;

	this.base = wtWidget;
	this.base(_parent, "table");

	$_(this).style.width = dimension(_width);
	$_(this).thead = new wtWidget(this, "tbody");
	$_(this).thead.setDisplay(false);
	$_(this).tshead = new wtWidget(this, "tbody");
	$_(this).tshead.setDisplay(false);
	$_(this).tbody = new wtWidget(this, "tbody");
	$_(this).tstatus = new wtWidget(this, "tbody");
	$_(this).tstatus.setDisplay(false);
	$_(this).className += " wtDisplay";
	$_(this).border = $_(this).cellPadding = 0;
	$_(this).cellSpacing = 1;
	$_(this).arrow = null;
	$_(this).sortCell = null;

	var sortSlot = function(target, evt, source)
	{
		if ($_(target).colList == undefined) return;
		var colIndex = source.colIndex();
		if (colIndex >= $_(target).colList.length) return;
		var sortFactor = $_(target).colList[colIndex];
		if (sortFactor == 0) return;
		var defaultSortFunc = function(a, b)
		{
			if (a.getValue() < b.getValue()) return -1 * sortFactor;
			if (a.getValue() == b.getValue()) return 0;
			return sortFactor;
		}
		var rowArray = [];
		for(var i=0;i<$_($_(target).tbody).rows.length;i++)
		{
			rowArray.push(_$($_($_(target).tbody).rows.item(i)));
			rowArray[i].setDataColumn(colIndex);
		}
		rowArray.sort(defaultSortFunc);
		$_(target).tbody.clearAll();
		while(rowArray.length)
			target.addWidget(rowArray.shift());

		// put the up/down arrow to the appropriate cell
		// there are literally millions of ways to do this
		// but due to IE bugs, you have to try a few until you arrive at
		// this working implementation
		if ($_(target).arrow)
		{
			$_(target).arrow.removeSelf();
			$_(target).arrow = null;
		}
		if ($_(target).colList[colIndex] > 0)
			$_(target).arrow = new wtImage(null, "images/UpArrow.png");
		else
			$_(target).arrow = new wtImage(null, "images/DownArrow.png");
		source.addWidget($_(target).arrow);
		$_(target).arrow.setRelativePosition(0,-5);

		// reverse the polarity
		$_(target).colList[colIndex] *= -1;
		for(var i = 0; i<$_(target).colList.length;i++)
			if (i!=colIndex) $_(target).colList[i] = Math.abs($_(target).colList[i]);

		// remember which cell is sorted and apply the appropriate styles
		if ($_(target).sortCell)
			$_($_(target).sortCell).className = $_($_(target).sortCell).className.replace("DisplaySubtitleSorted", "DisplaySubtitleInactive");
		$_(target).sortCell = source;
		$_($_(target).sortCell).className = 
			$_($_(target).sortCell).className.replace(new RegExp("(DisplaySubtitleInactive|DisplaySubtitleActive)"), "DisplaySubtitleSorted");

		// emit a sort signal for outsiders
		target.emit("Sort", {"colIndex" : colIndex, "order" : $_(target).colList[colIndex] * -1});
	}
	this.setSlot("Sort", sortSlot);
	var activateColumnSlot = function(target, evt, source)
	{
		if ($_(target).colList == undefined) return;
		var colIndex = source.colIndex();
		if (colIndex >= $_(target).colList.length) return;
		if ($_(target).colList[colIndex] == 0) return;
		$_(source).className = $_(source).className.replace("DisplaySubtitleInactive", "DisplaySubtitleActive");
	}
	this.setSlot("ActivateColumn", activateColumnSlot);
	var deactivateColumnSlot = function(target, evt, source)
	{
		if ($_(target).colList == undefined) return;
		var colIndex = source.colIndex();
		if (colIndex >= $_(target).colList.length) return;
		if ($_(target).colList[colIndex] == 0) return;
		$_(source).className = $_(source).className.replace("DisplaySubtitleActive", "DisplaySubtitleInactive");
	}
	this.setSlot("DeactivateColumn", deactivateColumnSlot);
	this.setSignal("Sort");
}
wtDisplay.prototype = new wtWidget;
/**
  @private
  */
wtDisplay.prototype._wtWidget_addWidget = wtWidget.prototype.addWidget;
/**
  Adds a display row to this display table
  @param {wtDisplayRow} widget The display row to be added
  @return The added widget
  @type {wtWidget}
  */
wtDisplay.prototype.addWidget = function(widget)
{
	if (!$_(this).tbody || !$_(this).wtSignals.Sort)
		this._wtWidget_addWidget(widget);
	else
		return $_(this).tbody.addWidget(widget);
}
/**
  Sets the title, the title is usually a string, but it can also be a wtWidget
  @param {String|wtWidget} title The title
  */
wtDisplay.prototype.setTitle = function(title)
{
	this.unsetTitle();
	var tcell = new wtWidget(new wtWidget($_(this).thead, "tr"), "td");
	tcell.addWidget(title);
	$_(tcell).className += " DisplayTitle";
	$_(tcell).colSpan = 40;
	tcell.setSelectable(false);
	$_(this).thead.setDisplay(true);
}
/**
  Clears the title
  */
wtDisplay.prototype.unsetTitle = function()
{
	$_(this).thead.clearAll();
	$_(this).thead.setDisplay(false);
}
/**
  Adds a row with a label at the left and a widget at the right
  @param {String|wtWidget} label The left side label
  @param {wtWidget|String} widget The right side widget
  @returns The new row created
  @type wtWidget
  */
wtDisplay.prototype.setSimpleRow = function(label, widget)
{
	var retval = new wtWidget(this, "tr");
	var captionCell = new wtWidget(retval, "td");
	captionCell.addWidget(label);
	$_(captionCell).className += " DisplayCaption";
	captionCell.setSelectable(false);
	var contentCell = new wtDisplayCell(widget);
	if (isString(widget) || isNumber(widget))
		contentCell.setValue(widget);
	retval.addWidget(contentCell);
	$_(contentCell).className += " DisplayContent";
	$_(retval).captionCell = captionCell;
	$_(retval).contentCell = contentCell;
	retval.addWidget = function(widget){return $_(retval).contentCell.addWidget(widget);}
	return retval;
}
/**
  Adds a row with a list of widgets
  @param {Array} displayrow Array of widgets to be added
  @returns The new row created
  @type wtDisplayRow
 */
wtDisplay.prototype.setDisplayRow = function(displayrow)
{
	var retval = new wtDisplayRow(this);
	for(var i=0;i<displayrow.length;i++)
	{
		var cell = retval.addWidget(displayrow[i]);
		$_(cell).className += " DisplayContent";
	}
	return retval;
}
/**
  Deletes one of the child display rows
  @param {Integer} rowIdx The row index
  */
wtDisplay.prototype.delDisplayRow = function(rowIdx)
{
	_$($_(this).tbody.rows.item(rowIdx)).removeSelf();
}
/**
  Adds a subtitle row that indicates the type of objects displayed in each of the columns of display table, and can be used for sorting
  @param {Array} displayrow List of widgets to be added as the subtitle row
  @return The subtitle row
  @type wtDisplayRow
  */
wtDisplay.prototype.setSubtitleRow = function(displayrow)
{
	var retval = new wtDisplayRow($_(this).tshead);
	$_(this).colList = [];
	for(var i=0;i<displayrow.length;i++)
	{
		var cell = retval.addWidget(displayrow[i]);
		$_(cell).className += " DisplaySubtitleInactive";
		$_(this).colList.push(1);
		cell.connect("sort", "Click", this, "Sort");
		cell.connect("activate", "MouseOver", this, "ActivateColumn");
		cell.connect("deactivate", "MouseOut", this, "DeactivateColumn");
	}
	retval.setSelectable(false);
	$_(this).tshead.setDisplay(true);
	return retval;
}
/**
  Removes the subtitle row
  */
wtDisplay.prototype.unsetSubtitleRow = function()
{
	$_(this).tshead.clearAll();
	$_(this).tshead.setDisplay(false);
}
/**
  Adds a status row
  @param {wtWidget|String} widget The widget to be displayed on the status row
  @returns The newly created status row
  @type wtDisplayRow
  */
wtDisplay.prototype.setStatusRow = function(widget)
{
	$_(this).tstatus.clearAll();
	var retval = new wtDisplayRow($_(this).tstatus);
	var cell = retval.addWidget(widget);
	$_(cell).className += " DisplayStatus";
	$_(cell).colSpan = 50;
	$_(this).tstatus.setDisplay(true);
	return retval;
}
/**
  Removes the status row
  */
wtDisplay.prototype.unsetStatusRow = function()
{
	$_(this).tstatus.clearAll();
	$_(this).tstatus.setDisplay(false);
}
/**
  Sets which columns to enable display table sorting. <br/><br/>
  e.g. For a display table with 5 columns<br/>
  <i>displayTable.setSortEnabled([1,1,0,0,0])</i><br/>
  means the first two columns are sortable, while the last three columns cannot be used for sorting
  @param {Array} colList Array for selecting which columns are sortable
  */
wtDisplay.prototype.setSortEnabled = function(colList)
{
	$_(this).colList = colList;
}
/**
  Sorts the table according to the data value order of rows on the <i>colIndex</i> column
  @param {Integer} colIndex The column index at which row data values are retrieved and compared for sorting
  */
wtDisplay.prototype.sort = function(colIndex)
{
	$_(this).wtSlots.Sort(this, null, _$($_($_(this).tshead).rows.item(0).cells.item(colIndex)));
}
/**
  Tells the data values of all display cells in the display table
  @returns All data values
  @type Array
  */
wtDisplay.prototype.getValueArray = function()
{
	var retval = [];
	for(var i=0;i<$_($_(this).tbody).rows.length;i++)
		retval.push(_$($_($_(this).tbody).rows.item(i)).getValueList());
	return retval;
}
// }}}
// {{{ wtPopupMenu - basic popup menu with soft shadow, not meant to be used directly
POPUP_LEFT = 0;
POPUP_RIGHT = 1;
POPUP_TOP = 2;
POPUP_BOTTOM = 3;
window.currentMenu = null;

/**
  Constructs a popup menu.
  @constructor
  @class A basic popup menu with soft drop shadow, this class is not meant to be used in a web application directly. 
  This is only a base class for constructing other popup menus. Available signals: <br/>
  <ul>
  <li>PopUp</li>
  <li>PopOut</li>
  </ul>
  @param {wtWidget} parent The widget to attach this popup menu to.
  @param {Integer} popmode The direction of the popup menu. There are only four possible values for popmode:<br/>
  <ul>
  <li>POPUP_LEFT</li>
  <li>POPUP_RIGHT</li>
  <li>POPUP_TOP</li>
  <li>POPUP_BOTTOM</li>
  </ul>
  <br/><br/>
  */
var wtPopupMenu = function(parentWidget, popmode)
{
	if (arguments.length < 1)
		return;

	this.base = wtShadowWidget;
	this.base(document.body, 5);

	$_(this).wtDependency = parentWidget.toString();
	$_(this).table = new wtWidget(this, "table");
	$_($_(this).table).cellPadding = $_($_(this).table).border = 0;
	$_($_(this).table).cellSpacing = 1;
	$_(this).tbody = new wtWidget($_(this).table, "tbody");
	$_($_(this).table).className += " wtPopupMenu";
	$_(this).popMode = (popmode != undefined ? popmode : POPUP_BOTTOM);
	$_(this).parentWidget = parentWidget;
	$_(this).currentAlpha = 0.0;
	this.setDisplay(false);
	this.setLevel(50000);

	this.setAlpha(0.0);

	this.setSignal("PopUp");
	this.setSignal("PopOut");
	var popUpSlot = function(myself, evt, source)
	{
		myself.popUp();
	}
	this.setSlot("PopUp", popUpSlot);
	var checkCursorSlot = function(myself, evt, source)
	{
		var popOutFunc = function(){if ($_(myself)) myself.popOut();}
		window.popOutTimer = setTimeout(popOutFunc, 600);
	}
	this.setSlot("CheckCursor", checkCursorSlot);
	var cancelTimeoutSlot = function(myself, evt, source)
	{
		if (window.popOutTimer != undefined)
		{
			clearTimeout(window.popOutTimer);
			window.popOutTimer = undefined;
		}
	}
	this.setSlot("CancelTimeout", cancelTimeoutSlot);
	var closePopUpSlot = function(myself, evt, source)
	{
		if (currentMenu)
		{
			if (currentMenu == this)
				return;
			if (window.popOutTimer != undefined)
			{
				clearTimeout(window.popOutTimer);
				window.popOutTimer = undefined;
			}
			if (window.fadeInTimer != undefined)
			{
				clearTimeout(window.fadeInTimer);
				window.fadeInTimer = undefined;
			}
			currentMenu.popOut();
		}
	}
	this.setSlot("ClosePopUp", closePopUpSlot);

	parentWidget.connect("menu_popup", "MouseOver", this, "PopUp");
	parentWidget.connect("menu_check_cursor", "MouseOut", this, "CheckCursor");
	this.connect("menu_check_cursor", "MouseOut", this, "CheckCursor");
	parentWidget.connect("menu_cancel_timeout", "MouseOver", this, "CancelTimeout");
	this.connect("menu_cancel_timeout", "MouseOver", this, "CancelTimeout");
	window.mouse.connect(this.toString(), "Click", this, "ClosePopUp");
}
wtPopupMenu.prototype = new wtShadowWidget;
/**
  @private
  */
wtPopupMenu.prototype._wtShadowWidget_addWidget = wtShadowWidget.prototype.addWidget;
/**
  Adds a widget to be one of the selectable items in the popup menu
  @param {String|wtWidget} widget The widget to be appeared as a menu item
  @param {Function} handler The menu item handler.
  Input arguments of the handler follow the universal event handler format in WT Toolkit.
  @see wtObject#connect
  */
wtPopupMenu.prototype.addWidget = function(widget, handler)
{
	if (!$_(this).wtSlots.ClosePopUp)
	{
		this._wtShadowWidget_addWidget(widget);
		return;
	}
	var row = new wtWidget($_(this).tbody, "tr");
	var cell = new wtWidget(row, "td");
	$_(cell).className += " PopupItemInactive";
	cell.addWidget(widget);
	if (handler)
	{
		cell.setSlot("ClickHandler", handler);
		cell.connect("menuitem_click", "Click", cell, "ClickHandler");
	}
	var activate = function(myself, evt, source)
	{
		$_(myself).className = $_(myself).className.replace("PopupItemInactive", "PopupItemActive");
	}
	var deactivate = function(myself, evt, source)
	{
		$_(myself).className = $_(myself).className.replace("PopupItemActive", "PopupItemInactive");
	}
	cell.setSlot("Activate", activate);
	cell.setSlot("Deactivate", deactivate);
	cell.connect("menuitem_activate", "MouseOver", cell, "Activate");
	cell.connect("menuitem_deactivate", "MouseOut", cell, "Deactivate");
	return cell;
}
/**
  Adds a list of items with their corresponding event handlers to the popup menu
  @param {Array} widgetList The list of widgets or strings
  @param {Array} handlerList The list of event handlers
  Input arguments of the handler follow the universal event handler format in WT Toolkit.
  @see wtObject#connect
  */
wtPopupMenu.prototype.addItems = function(widgetList, handlerList)
{
	if (handlerList)
	{
		for(var i=0;i<widgetList.length;i++)
			this.addWidget(widgetList[i], handlerList[i]);
	}
	else
	{
		for(var i=0;i<widgetList.length;i++)
			this.addWidget(widgetList[i]);
	}
}
/**
  Makes the menu apear around a screen position
  @param {Number} _x The position on x-axis
  @param {Number} _y The position on y-axis
  */
wtPopupMenu.prototype.popUp = function(_x, _y)
{
	if (currentMenu)
	{
		if (currentMenu == this)
			return;
		if (this.get("parentWidget").isAncestorOf(currentMenu.get("parentWidget")))
			return;
		if (window.popOutTimer != undefined)
		{
			clearTimeout(window.popOutTimer);
			window.popOutTimer = undefined;
		}
		if (window.fadeInTimer != undefined)
		{
			clearTimeout(window.fadeInTimer);
			window.fadeInTimer = undefined;
		}
		currentMenu.popOut();
	}
	currentMenu = this;
	this.setDisplay(true);
	var menu = this;
	var fadeIn = function()
	{
		if ($_(menu).currentAlpha > 0.95)
		{
			window.fadeInTimer = undefined;
			return;
		}
		$_(menu).currentAlpha += 0.1;
		menu.setAlpha($_(menu).currentAlpha);
		window.fadeInTimer = setTimeout(fadeIn, 30);
	}
	if (!isMSIE())
		window.fadeInTimer = setTimeout(fadeIn, 30);
	else
		this.setAlpha(1);
	if (_x != undefined && _y != undefined)
		this.setAbsolutePosition(_x, _y);
	else
	{
		var pt = this.getAttachCoordinate();
		this.setAbsolutePosition(pt.x, pt.y);
	}
	this.emit("PopUp", {});
}
/**
  Makes the popup menu disappear
  */
wtPopupMenu.prototype.popOut = function()
{
	if (currentMenu && currentMenu != this)
		currentMenu.popOut();
	this.setDisplay(false);
	$_(this).currentAlpha = 0.0;
	this.setAlpha(0.0);
	currentMenu = null;
	if (window.popOutTimer)
	{
		clearTimeout(window.popOutTimer);
		window.popOutTimer = undefined;
	}
	if (window.fadeInTimer)
	{
		clearTimeout(window.fadeInTimer);
		window.fadeInTimer = undefined;
	}
	this.emit("PopOut", {});
}
/**
  Tells where the popup menu should appear according to its <i>popmode</i>  <br/>
  @returns "x": current x-axis position, "y": current y-axis position 
  @type Object
  */
wtPopupMenu.prototype.getAttachCoordinate = function()
{
	var parentPos = $_(this).parentWidget.getScreenPosition();
	if (isMSIE())
	{
		parentPos.x += document.documentElement.scrollLeft;
		parentPos.y += document.documentElement.scrollTop;
	}
	else
	{
		parentPos.x += window.scrollX;
		parentPos.y += window.scrollY;
	}
	var x, y;
	if ($_(this).popMode == POPUP_LEFT)
	{
		x = parentPos.x - $_($_(this).table).offsetWidth;
		y = parentPos.y;
	}
	else if ($_(this).popMode == POPUP_RIGHT)
	{
		x = parentPos.x + $_($_(this).parentWidget).offsetWidth;
		y = parentPos.y;
	}
	else if ($_(this).popMode == POPUP_TOP)
	{
		x = parentPos.x;
		y = parentPos.y - $_($_(this).table).offsetHeight;
	}
	else
	{
		x = parentPos.x;
		y = parentPos.y + $_($_(this).parentWidget).offsetHeight;
	}
	return {"x":x, "y":y};
}
/**
  Sets the size of the popup menu, useful for extending the width of popup menues.
  @param {String} width The widget's width as a CSS length quantity.
  @param {String} height The spacer's height as a CSS length quantity.
  */
wtPopupMenu.prototype.setSize = function(width, height)
{
	$_(this).table.setSize(width, height);
}
/**
  Adds a separator to the popup menu.
  */
wtPopupMenu.prototype.addSeparator = function()
{
	var row = new wtWidget($_(this).tbody, "tr");
}
// }}} 
// {{{ wtAttachedMenu - a popup menu attached to some widget
/**
  Constructs a popup menu attached to another widget. The attached popup menu appears when the mouse cursor is over the attached widget. 
  @constructor
  @class A popup menu attached to some widget. 
  @param {wtWidget} parent The widget to attach this popup menu to.
  @param {Integer} popmode The direction of the popup menu. There are only four possible values for popmode:<br/>
  <ul>
  <li>POPUP_LEFT</li>
  <li>POPUP_RIGHT</li>
  <li>POPUP_TOP</li>
  <li>POPUP_BOTTOM</li>
  </ul>
  */
var wtAttachedMenu = function(parent, popmode)
{
	this.base = wtPopupMenu;
	this.base(parent, popmode);
}
wtAttachedMenu.prototype = new wtPopupMenu;
// }}}
// {{{ wtContextMenu - a popup menu that appears when the user right clicks on a widget
/**
  Constructs a context menu. The context menu appears when the attached widget is being right clicked.
  @constructor
  @class A popup menu that appears when the user right clicks on a widget. Available signals: <br/>
  <ul>
  <li>ContextMenu</li>
  </ul>
  @param {wtWidget} parent The widget to attach this popup menu to.
  */
var wtContextMenu = function(parentWidget, width)
{
	if (arguments.length < 1)
		return;

	this.base = wtPopupMenu;
	this.base(parentWidget);
	this.set("wtDependency", parentWidget);

	if (width)
		this.setSize(width, "");

	parentWidget.linkSignal("ContextMenu", "oncontextmenu");
	parentWidget.set("oncontextmenu_raw", parentWidget.get("oncontextmenu"));
	var contextHandler = function(evt)
	{
		this.oncontextmenu_raw(evt);
		return false;
	}
	parentWidget.set("oncontextmenu", contextHandler);

	var popUpSlot = function(myself, evt, source)
	{
		var scrollOffsetX, scrollOffsetY;
		if (isMSIE())
		{
			scrollOffsetX = document.documentElement.scrollLeft;
			scrollOffsetY = document.documentElement.scrollTop;
		}
		else
		{
			scrollOffsetX = window.scrollX;
			scrollOffsetY = window.scrollY;
		}
		myself.popUp(mouse.x +scrollOffsetX -3, mouse.y +scrollOffsetY -3);
	}
	this.setSlot("PopUp", popUpSlot);

	parentWidget.disconnect("menu_popup", "MouseOver");
	parentWidget.disconnect("menu_check_cursor", "MouseOut");
	parentWidget.disconnect("menu_cancel_timeout", "MouseOver");
	parentWidget.connect("menu_popup", "ContextMenu", this, "PopUp");
}
wtContextMenu.prototype = new wtPopupMenu;
// }}}
// {{{ wtNotebookPage - tabbed page container
/**
  Constructs a tabbed page container for use with wtNotebook.
  @constructor
  @class A tabbed page container for use with wtNotebook. Available signals: <br/>
  <ul>
  <li>Select</li>
  <li>Deselect</li>
  </ul>
  @param {wtNotebook} notebook The parent wtNotebook container.
  @param {String|wtWidget} title The tab caption of this notebook page.
  @see wtNotebook
  */
var wtNotebookPage = function(notebook, title)
{
	if (arguments.length < 2)
		return;

	this.startProxy(this);

	$_(this).notebook = notebook;
	$_(this).wtDependency = notebook;
	var tab = new wtRowLayout($_(notebook).tabLayout, "");
	$_(this).wtDependency = tab.toString();
	$_(this).tab = tab;
	$_(tab).leftCell = tab.addWidget("");
	$_(tab).centerCell = tab.addWidget("");
	$_($_(tab).centerCell).className += " TabTitle";
	$_(tab).rightCell = tab.addWidget("");
	tab.setSelectable(false);

	if (isMSIE())
	{
		$_($_(tab).leftCell).style.filter += 
			" progid:DXImageTransform.Microsoft.AlphaImageLoader(src='images/TabInactiveLeft.png',sizingMethod='scale')";
		$_($_(tab).centerCell).style.filter += 
			" progid:DXImageTransform.Microsoft.AlphaImageLoader(src='images/TabInactiveCenter.png',sizingMethod='scale')";
		$_($_(tab).rightCell).style.filter += 
			" progid:DXImageTransform.Microsoft.AlphaImageLoader(src='images/TabInactiveRight.png',sizingMethod='scale')";
	}
	else
	{
		$_($_(tab).leftCell).style.backgroundImage = "url(images/TabInactiveLeft.png)";
		$_($_(tab).centerCell).style.backgroundImage = "url(images/TabInactiveCenter.png)";
		$_($_(tab).rightCell).style.backgroundImage = "url(images/TabInactiveRight.png)";
	}
	$_(tab).leftCell.setSize(25, 28);
	$_(tab).rightCell.setSize(25, 28);
	$_(tab).centerCell.addWidget(title);
	var contentBlock = new wtView($_(notebook).contentCell, "100%", "100%");
	$_(this).contentBlock = contentBlock;
	if ($_(notebook).parentNode == document.body)
		$_(contentBlock).style.overflow = "";
	contentBlock.setDisplay(false);
	$_(contentBlock).className += " TabView";
	$_(this).selected = false;

	var activateSlot = function(myself, evt, source)
	{
		if ($_(myself).selected)
			return;
		if (navigator.userAgent.search("MSIE") != -1)
		{
			$_($_($_(myself).tab).leftCell).filters.item("DXImageTransform.Microsoft.AlphaImageLoader").src = "images/TabActiveLeft.png";
			$_($_($_(myself).tab).centerCell).filters.item("DXImageTransform.Microsoft.AlphaImageLoader").src = "images/TabActiveCenter.png";
			$_($_($_(myself).tab).rightCell).filters.item("DXImageTransform.Microsoft.AlphaImageLoader").src = "images/TabActiveRight.png";
		}
		else
		{
			$_($_($_(myself).tab).leftCell).style.backgroundImage = "url(images/TabActiveLeft.png)";
			$_($_($_(myself).tab).centerCell).style.backgroundImage = "url(images/TabActiveCenter.png)";
			$_($_($_(myself).tab).rightCell).style.backgroundImage = "url(images/TabActiveRight.png)";
		}
	}
	this.setSlot("Activate", activateSlot);
	var deactivateSlot = function(myself, evt, source)
	{
		if ($_(myself).selected)
			return;
		if (navigator.userAgent.search("MSIE") != -1)
		{
			$_($_($_(myself).tab).leftCell).filters.item("DXImageTransform.Microsoft.AlphaImageLoader").src = "images/TabInactiveLeft.png";
			$_($_($_(myself).tab).centerCell).filters.item("DXImageTransform.Microsoft.AlphaImageLoader").src = "images/TabInactiveCenter.png";
			$_($_($_(myself).tab).rightCell).filters.item("DXImageTransform.Microsoft.AlphaImageLoader").src = "images/TabInactiveRight.png";
		}
		else
		{
			$_($_($_(myself).tab).leftCell).style.backgroundImage = "url(images/TabInactiveLeft.png)";
			$_($_($_(myself).tab).centerCell).style.backgroundImage = "url(images/TabInactiveCenter.png)";
			$_($_($_(myself).tab).rightCell).style.backgroundImage = "url(images/TabInactiveRight.png)";
		}
	}
	this.setSlot("Deactivate", deactivateSlot);
	this.setSignal("Select");
	this.setSignal("Deselect");

	tab.connect("tab_activate", "MouseOver", this, "Activate");
	tab.connect("tab_deactivate", "MouseOut", this, "Deactivate");
	tab.connect("tab_select", "Click", notebook, "SelectTab");
}
wtNotebookPage.prototype = new wtObject;
/**
  Removes a notebook page.
  */
wtNotebookPage.prototype.removeSelf = function()
{
	var tab = $_(this).tab;
	var contentBlock = $_(this).contentBlock;
	tab.removeSelf();
	contentBlock.removeSelf();
	var tabList = $_($_(this).notebook).tabList;
	for(var i=0;i<tabList.length;i++)
	{
		if (tabList[i] == this)
		{
			tabList.splice(i, 1);
			break;
		}
	}
	this.endProxy();
}
/**
  Adds a widget into the notebook page.
  @param {wtWidget|String} widget The wtWidget to be added. Alternatively, you may add a string to be displayed inside the notebook.
  */
wtNotebookPage.prototype.addWidget = function(widget)
{
	return $_(this).contentBlock.addWidget(widget);
}
/**
  Sets the tab caption of the notebook page.
  @param {String|wtWidget} title The new tab caption of this notebook page.
  */
wtNotebookPage.prototype.setTitle = function(title)
{
	$_($_(this).tab).centerCell.clearAll();
	$_($_(this).tab).centerCell.addWidget(widget);
}
/**
  Selects a notebook page and makes it the page being displayed in the wtNotebook.
  */
wtNotebookPage.prototype.select = function()
{
	var tab = $_(this).tab;
	var leftCell = $_(tab).leftCell;
	var centerCell = $_(tab).centerCell;
	var rightCell = $_(tab).rightCell;
	if (isMSIE())
	{
		$_(leftCell).filters.item("DXImageTransform.Microsoft.AlphaImageLoader").src = "images/TabSelectedLeft.png";
		$_(centerCell).filters.item("DXImageTransform.Microsoft.AlphaImageLoader").src = "images/TabSelectedCenter.png";
		$_(rightCell).filters.item("DXImageTransform.Microsoft.AlphaImageLoader").src = "images/TabSelectedRight.png";
	}
	else
	{
		$_(leftCell).style.backgroundImage = "url(images/TabSelectedLeft.png)";
		$_(centerCell).style.backgroundImage = "url(images/TabSelectedCenter.png)";
		$_(rightCell).style.backgroundImage = "url(images/TabSelectedRight.png)";
	}
	$_(this).selected = true;
	$_(this).contentBlock.setDisplay(true);
	this.emit("Select", {});
}
/**
  Deselects the notebook page. This sets the wtNotebook to display nothing.
  */
wtNotebookPage.prototype.deselect = function()
{
	$_(this).selected = false;
	$_(this).wtSlots.Deactivate(this);
	$_(this).contentBlock.setDisplay(false);
	this.emit("Deselect", {});
}
/**
  Clears the contents of the notebook page.
  */
wtNotebookPage.prototype.clearAll = function()
{
	$_(this).contentBlock.clearAll();
}
// }}}
// {{{ wtNotebook - basic tabbed container
/**
  Constructs a tabbed container. <br/>
  @constructor
  @class A basic tabbed container.
  @param {wtWidget|DOM_Node} parent The parent container of this widget.
  @see wtNotebookPage
  */
var wtNotebook = function(parent)
{
	if (arguments.length < 1)
		return;

	this.base = wtWidget;
	this.base(parent, "div");

	$_(this).className += " wtNotebook";
	$_(this).tabCell = new wtWidget(this, "div");
	$_(this).tabLayout = new wtRowLayout($_(this).tabCell, "");
	var separator = new wtWidget(this, "div");
	$_(separator).style.backgroundColor = "#536baa";
	separator.setSize("100%", 3);
	$_(separator).style.margin = "0px 0px 0px 0px";
	$_(separator).style.padding = "0px";
	$_(separator).style.fontSize = "0";		// this is for solving a hideous IE layout bug
	$_(this).contentCell = new wtWidget(this, "div");
	var contentCell = $_(this).contentCell;
	$_(this).style.width = $_(this).style.height = "100%";
	if (parent != document.body)
	{
		$_(contentCell).style.width = (parseInt($_(this).parentNode.offsetWidth) - 4) + "px";
		$_(contentCell).style.height = (parseInt($_(this).parentNode.offsetHeight) - 32) + "px";
	}
	else
	{
		$_(contentCell).style.width = "100%";
		$_(contentCell).style.height = "100%";
	}
	$_(this).tabList = [];

	this.setAbsolutePosition(0, 0);

	var selectTabSlot = function(myself, evt, source)
	{
		try
		{
			for(var i=0;i<$_(myself).tabList.length;i++)
			{
				if ($_($_(myself).tabList[i]).tab == source)
					$_(myself).tabList[i].select();
				else
					$_(myself).tabList[i].deselect();
			}
		}
		catch(e){}
	}
	this.setSlot("SelectTab", selectTabSlot);
}
wtNotebook.prototype = new wtWidget;
/**
  Adds a new notebook page.
  @param {String|wtWidget} pageTitle The tab caption of the new notebook page.
  @returns The new notebook page.
  @type wtNotebookPage
  */
wtNotebook.prototype.newPage = function(pageTitle)
{
	var retval = new wtNotebookPage(this, pageTitle);
	$_(this).tabList.push(retval);
	return retval;
}
/**
  Removes an existing child notebook page.
  @param {Integer} page The index of the notebook page. The leftmost notebook page has an index of 0.
  */
wtNotebook.prototype.removePage = function(page)
{
	if (isInteger(page))
		$_(this).tabList[page].removeSelf();
	else
		page.removeSelf();
}
// }}}
// {{{ wtTreeNode - tree node, freely expandable to form a tree
/**
  Constructs a tree node.
  @constructor
  @class A tree node, freely expandable to form a tree.
  @param {wtWidget|DOM_Node} parent The parent container of this widget.
  @param {wtWidget|String} caption The caption of the tree node.
  */
var wtTreeNode = function(parentWidget, caption)
{
	if (arguments.length < 2)
		return;

	this.base = wtColumnLayout;
	this.base(parentWidget, "");

	$_(this).className += " wtTreeNode";
	$_(this).nodeCell = this.addWidget("");
	var c = new wtRowLayout(this, "100%");
	c.addSpacer(18);
	this.set("childRow", c);
	$_(this).childLayout = new wtColumnLayout(c, "");
	this.get("childLayout").get("style").width = "100%";
	$_(this).nodeLayout = new wtRowLayout($_(this).nodeCell, "");
	$_(this).indicatorCell = $_(this).nodeLayout.addWidget(new wtImage(null, "images/IndicatorMinus.png"));
	$_(this).indicatorCell.setVisible(false);
	$_(this).nodeLayout.addSpacer(5);
	$_(this).imageCell = $_(this).nodeLayout.addWidget(new wtImage(null, "redist/continuum/16x16/mimetypes/image_alt.png"));
	$_(this).nodeLayout.addSpacer(5);
	$_(this).anchorCell = $_(this).nodeLayout.addWidget($_(this).anchor = new wtAnchor(null, caption));
	$_(this).opened = true;
	$_(this).isLeaf = true;
	c.setDisplay(false);
	this.setSelectable(false);

	var toggleSlot = function(myself, evt, source)
	{
		$_(myself).opened = !$_(myself).opened;
		myself.setOpened($_(myself).opened);
	}
	this.setSlot("Toggle", toggleSlot);

	$_(this).indicatorCell.connect("treenode_toggle", "Click", this, "Toggle");
	$_(this).imageCell.connect("treenode_toggle_2", "Click", this, "Toggle");
}
wtTreeNode.prototype = new wtColumnLayout;
/**
  Sets the tree node to appear as selected or not.
  @param {Boolean} yes Whether the tree node is selected or not.
  */
wtTreeNode.prototype.setSelected = function(yes){$_(this).anchor.setSelected(yes);}
/**
  Sets the tree node to be enabled or not.
  @param {Boolean} yes Whether the tree node is enabled or not.
  */
wtTreeNode.prototype.setEnabled = function(yes)
{
	$_(this).wtDisabled = !yes;
	$_(this).anchor.setEnabled(yes);
}
/**
  Tells whether the tree node is currently enabled or not.
  @returns Whether the tree node is currently enabled or not.
  @type Boolean
  */
wtTreeNode.prototype.isEnabled = function()
{
	return !($_(this).wtDisabled);
}
/**
  Sets the tree node to link to a URL.
  @param {String} href A valid URL.
  */
wtTreeNode.prototype.setHref = function(href){$_(this).anchor.setHref(href);}
/**
  Removes a tree node's hyperlink property.
  */
wtTreeNode.prototype.resetHref = function(){$_(this).anchor.resetHref();}
/**
  Sets a click event handler to the tree node.
  @param {Function} handler The click handler.
  Input arguments of the handler follow the universal event handler format in WT Toolkit.
  @see wtObject#connect
  */
wtTreeNode.prototype.setHandler = function(handler){$_(this).anchor.setHandler(handler);}
/**
  Removes the tree node's click event handler.
  */
wtTreeNode.prototype.resetHandler = function(){$_(this).anchor.resetHandler();}
/**
  Sets a tree node to be opened or not. Children nodes under a tree node are only visible if the tree node is opened.
  @param {Boolean} yes Whether the tree node is opened or not.
  */
wtTreeNode.prototype.setOpened = function(yes)
{
	if (yes)
	{
		$_(this).childRow.setDisplay(true);
		$_(this).indicatorCell.clearAll();
		$_(this).indicatorCell.addWidget(new wtImage(null, "images/IndicatorMinus.png"));
	}
	else
	{
		$_(this).childRow.setDisplay(false);
		$_(this).indicatorCell.clearAll();
		$_(this).indicatorCell.addWidget(new wtImage(null, "images/IndicatorPlus.png"));
	}
	this.set("opened", yes);
}
/**
  @private
  */
wtTreeNode.prototype._wtColumnLayout_addWidget = wtColumnLayout.prototype.addWidget;
/**
  Adds a child node under the tree node.
  @param {wtTreeNode} Child node.
  @returns The table cell containing the child node.
  @type wtWidget
  */
wtTreeNode.prototype.addWidget = function(widget)
{
	if (!$_(this).wtSlots.Toggle)
	{
		return this._wtColumnLayout_addWidget(widget);
	}
	if ($_(this).isLeaf)
	{
		$_(this).isLeaf = false;
		$_(this).indicatorCell.setVisible(true);
		$_(this).imageCell.clearAll();
		$_(this).imageCell.addWidget(new wtImage(null, "redist/continuum/16x16/filesystems/folder.png"));
		if (this.get("opened"))
			this.get("childRow").setDisplay(true);
	}
	return $_(this).childLayout.addWidget(widget);
}
/**
  Removes a child node
  @param {wtWidget} A cell returned by wtTreeNode::addWidget()
  */
wtTreeNode.prototype.removeWidget = function(widget)
{
	var row = _$(widget.get("parentNode"));
	row.removeSelf();

	if (this.get("childLayout").get("rows").length < 1)
	{
		this.set("isLeaf", true);
		this.get("indicatorCell").setVisible(false);
		if (! this.get("iconPath"))
		{
			this.get("imageCell").clearAll();
			this.get("imageCell").addWidget(new wtImage(null, "redist/continuum/16x16/mimetypes/image_alt.png"));
		}
		this.get("childRow").setDisplay(false);
	}
}
/**
  Sets the tree node's icon.
  @param {String} iconPath The icon's URL.
  */
wtTreeNode.prototype.setIcon = function(iconPath)
{
	$_(this).imageCell.clearAll();
	this.set("iconPath", iconPath);
	$_(this).imageCell.addWidget(new wtImage(null, iconPath));
}
/**
  Clears the tree node's icon
  */
wtTreeNode.prototype.clearIcon = function()
{
	$_(this).imageCell.clearAll();
}
// }}}
// {{{ wtTextBlock - a block of text, with shadow
/**
  Constructs a shadowed text block.
  @class A shadowed text block.
  @param {wtWidget|DOM_Node} parentWidget The parent container for adding this widget to. Can also be a DOM node or null.
  @param {String} text The text contained in the text block.
  @constructor
  */
var wtTextBlock = function(parentWidget, text)
{
	if (arguments.length < 2)
		return;

	this.base = wtShadowWidget;
	this.base(parentWidget, 5);
	$_(this).className += " wtTextBlock";

	var contentCell = this.get("contentCell");
	$_(contentCell).className += " wtTextBlockContent";
	contentCell.get("style").border = "1px black solid";
	contentCell.addWidget(text);
}
wtTextBlock.prototype = new wtShadowWidget;
/**
  Sets the text content of the text block.
  @param {String} text The new text content.
  */
wtTextBlock.prototype.setText = function(text)
{
	var contentCell = this.get("contentCell");
	contentCell.clearAll();
	return contentCell.addWidget(text);
}
// }}}
// {{{ wtToolbarItem - a toolbar item with images and labels
/**
  @class A toolbar item of wtToolbar
  @private
  @param {wtWidget|DOM_Node} _parent The parent container
  @param {String} _name The item label 
  @param {String} _imageUrl The url of the image of the item
  @param {Number} _imageWidth The width of the image
  @param {Number} _imageHeight The height of the image
  */
var wtToolbarItem = function(_parent, _name, _imageUrl, _imageWidth, _imageHeight)
{
	this.base = wtWidget;
	this.base(_parent,"td");

	this.set("toolbar",_parent);

	var overItemHandler = function(widget, evt, source)
	{
		if (!widget.get("selected"))
			widget.set("bgColor","lightgrey");
	}
	var outItemHandler = function(widget, evt, source)
	{
		if (!widget.get("selected"))
			widget.set("bgColor","white");
	}
	var selectItemHandler = function(widget, evt, source)
	{
		widget.emit("UnselectOld");
		$_(widget).selected = true;
		widget.set("bgColor","lightgreen");
	}
	var unselectItemHandler = function(widget, evt, source)
	{
		$_(widget).selected = false;
		widget.set("bgColor","white");
	}

	$_(this).selected = false;
	this.setSignal("Unselect");

	this.setSlot("OverItemSlot",overItemHandler);
	this.setSlot("OutItemSlot",outItemHandler);
	this.setSlot("SelectItemSlot",selectItemHandler);
	this.setSlot("UnselectItemSlot",unselectItemHandler);
	this.connect("over_item","MouseOver",this,"OverItemSlot");
	this.connect("out_item","MouseOut",this,"OutItemSlot");
	this.connect("select_item","Click",this,"SelectItemSlot");
	this.connect("unselect_item","Unselect",this,"UnselectItemSlot");


	var layout = new wtColumnLayout(this,_imageWidth);
	var image = new wtImage(layout,_imageUrl);
	image.setSize(_imageWidth,_imageHeight);
	var textRow = new wtWidget(layout,"div");
	textRow.setSelectable(false);
	textRow.set("align","center");
	textRow.addWidget(_name);	
}
wtToolbarItem.prototype = new wtWidget;

wtToolbarItem.prototype.setHandler = function(_onClickHandler)
{
	if (_onClickHandler!=null)
	{
		this.setSlot("ClickItemSlot",_onClickHandler);
		this.connect("click_item","Click", this,"ClickItemSlot");
	}
}
// }}}
// {{{ wtToolbar - A toolbar with images and labels
/**
  @class A scrollable toolbar
  @private
  @param {wtWidget|DOM_Node} _parent The parent container
  @param {Number} _width The width of the toolbar
  @param {Number} _imageWidth The width of the image
  @param {Number} _imageHeight The height of the image
  */
var wtToolbar = function(_parent, _width, _imageWidth, _imageHeight)
{
	this.base = wtView
	this.base(_parent, _width, "auto");

	if (isMSIE())
	{
		this.get("style").overflow = "scroll";
	}
	this.set("align","left");
	var unselectAllHandler = function(widget, evt, source)
	{
		var item = widget.get("selectedItem");
		if (item!=null)
		{
			item.emit("Unselect");
		}
		widget.set("selectedItem",source);
	}

	$_(this).table = new wtWidget(this,"table");
	$_(this).table.set("border","1px");
	$_(this).table.set("borderColor","lightgrey");
	$_(this).tbody = new wtWidget(this.get("table"),"tbody");
	$_(this).trow = new wtWidget(this.get("tbody"),"tr");
	$_(this).trow.setSlot("UnselectOldItemSlot",unselectAllHandler);
	$_(this).trow.set("selectedItem",null);
	$_(this).imageWidth = _imageWidth;
	$_(this).imageHeight = _imageHeight;
}
wtToolbar.prototype = new wtWidget;
/**
  Appends an item to the end of the toolbar
  @param {String} _name The item label
  @param {String} _imageUrl The url of the image of the item
  @param {Function} _onClickHandler The click handler
  Input arguments of the handler follow the universal event handler format in WT Toolkit.
  @return The added item
  @type wtToolbarItem
  */
wtToolbar.prototype.addItem = function(_name, _imageUrl, _onClickHandler)
{
	return this.insertItem(this.getSize(),_name,_imageUrl,_onClickHandler);	
}
/**
  Adds an item to the toolbar at the given position, appends the item to the end of the toolbar if _index >= size of the toolbar.
  @param {Number} _index The index of the item
  @param {String} _name The item label
  @param {String} _imageUrl The url of the image of the item
  @param {Function} _onClickHandler The click handler
  Input arguments of the handler follow the universal event handler format in WT Toolkit.
  @return The added item
  @type wtToolbarItem
  */
wtToolbar.prototype.insertItem = function(_index, _name, _imageUrl, _onClickHandler)
{
	var _parent = this.get("trow");
	var retval = new wtToolbarItem(null,_name,_imageUrl,this.get("imageWidth"), this.get("imageHeight"));

	if (this.getItem(_index)==null)
		$_(_parent).appendChild($_(retval));
	else $_(_parent).insertBefore($_(retval),$_(this.getItem(_index)));
	retval.setSignal("UnselectOld");
	retval.connect("unselect_all_item","UnselectOld",this.get("trow"),"UnselectOldItemSlot");
	retval.setHandler(_onClickHandler);

	return retval;
}
/**
  Removes an item with given index from the toolbar
  */
wtToolbar.prototype.removeItem = function(_index)
{
	if (_index<0 || _index>=this.getSize())
		return;

	if (this.getItem(_index)!=null)
		this.getItem(_index).removeSelf();
}
/**
  Gets the selected item, return null if no item is selected.
  @return The index of the selected item 
  @type Number
  */
wtToolbar.prototype.getSelectedItem = function()
{
	return this.get("trow").get("selectedItem");
}
/**
  Gets the item of given index
  @return The item of given index
  @type wtToolbarItem
  */
wtToolbar.prototype.getItem = function(_index)
{
	if (_index<0 || _index>=this.getSize())
		return null;

	var retval = this.get("trow").get("childNodes")[_index];
	return _$(retval);
}
/**
  Gest the number of items
  @return The number of wtToolbarItem
  @type Number
  */
wtToolbar.prototype.getSize = function()
{
	return this.get("trow").get("childNodes").length;
}
//}}}

WT Toolkit 0.3.3

Documentation generated by JSDoc on Sun May 13 11:26:24 2007